我有一个订单交易数据集,如下表所示
1,John,iPhone Cover,9.99
2,Jack,iPhone Cover,9.99
4,Jill,Samsung Galaxy Cover,9.95
3,John,Headphones,5.49
5,Bob,iPad Cover,5.45
我正在考虑将某些差异中的数据分组到不同的交易中。例如,我将产品1,2,4分组到交易清单列表(1,2,4)中,因为它们的价格绝对差异小于1.另一方面,将产品3,5放入相同的交易列表中(3,5)。
我知道我可以在Python中使用以下代码完成此操作:
f = open('test.csv', 'r')
current_price = 0
res = []
ary = []
for id, line in enumerate(f.readlines()):
dt = line.strip().split(',')
if id ==0:
current_price = float(dt[3])
if abs(float(dt[3]) - current_price) < 1:
ary.append(dt[0])
else:
res.append(ary)
current_price = float(dt[3])
ary = [dt[0]]
res.append(ary)
print res
但是由于scala是函数式编程语言,如何用函数式编程风格实现同样的目标呢?
答案 0 :(得分:1)
这样的事情:
val xs = input.map(_.split(","))
//List(Array(1, John, iPhone Cover, 9.99),
// Array(2, Jack, iPhone Cover, 9.99),
// Array(4, Jill, Samsung Galaxy Cover, 9.95),
// Array(3, John, Headphones, 5.49),
// Array(5, Bob, iPad Cover, 5.45))
xs.tail.foldLeft((xs.head(3), List(List(xs.head(0))))) {
case ((cur, acc), e) =>
if (Math.abs(cur.toDouble - e(3).toDouble) < 1.0)
(cur, (acc.head :+ e(0)) :: acc.tail)
else (e(3), List(e(0)) :: acc)
}._2.reverse
//List(List(1, 2, 4), List(3, 5))
我们将每个迭代的当前组的当前价格和目前的组列表传递给每个迭代。如果当前价格足够接近下一个价格,我们将id添加到当前组。否则,我们从下一个元素开始一个新组,并将当前价格更改为该价格。
看起来比实际更复杂。如果我是真的这样做,我会做类似下面的事情 - 定义一个案例类来保存每一行的值,以及一个方法,以便&#34;足够接近价格&#34;。
case class Line(id: Int, person: String, product: String, price: Double) {
def closeEnough(other: Line) = (Math.abs(price - other.price) < 1.0)
}
然后从行
创建对象val xs = input.map { l => val xs = l.split(","); Line(xs(0).toInt, xs(1), xs(2), xs(3).toDouble) }
// List(Line(1,John,iPhone Cover,9.99),
// Line(2,Jack,iPhone Cover,9.99),
// Line(4,Jill,Samsung Galaxy Cover,9.95),
// Line(3,John,Headphones,5.49),
// Line(5,Bob,iPad Cover,5.45))
现在进行折叠,但使用Lines
val groups = xs.tail.foldLeft(List(List(xs.head))) {
case (acc, e) =>
if (e.closeEnough(acc.head.head))
(acc.head :+ e) :: acc.tail
else List(e) :: acc
}.reverse
如果需要,请转换为ID列表
groups.map(_.map(_.id))
// List(List(1, 2, 4), List(3, 5))