编辑:添加了以下事实:列表已排序,并且实现“重复”具有误导性,将其替换为标题中的“冗余”。
我有一个排序的条目列表,说明给定时间间隔内的生产值。在以后说明完全相同的值的条目不会添加任何信息,可以安全地省略。
case class Entry(minute:Int, production:Double)
val entries = List(Entry(0, 100.0), Entry(5, 100.0), Entry(10, 100.0), Entry(20, 120.0), Entry(30, 100.0), Entry(180, 0.0))
尝试使用scala 2.8集合函数,到目前为止,我有这个有效的实现:
entries.foldRight(List[Entry]()) {
(entry, list) => list match {
case head :: tail if (entry.production == head.production) => entry :: tail
case head :: tail => entry :: list
case List() => entry :: List()
}
}
res0: List[Entry] = List(Entry(0,100.0), Entry(20,120.0), Entry(30,100.0), Entry(180,0.0))
有何评论?我错过了一些斯卡拉魔法吗?
答案 0 :(得分:9)
当你比较列表中的连续条目时,从zip
开始 - 用它的尾部ping列表以获得连续元素对的列表。
下面,我从列表中选择第一个条目,并使用collect
同时过滤掉生产未更改的对,对于其余对,请映射e2
。 (collect
是Scala 2.8中的新功能,有一段时间称为partialMap
)
scala> entries.head :: ((entries zip entries.tail).collect {
case (Entry(_, p1), e2@Entry(_, p2)) if p1 != p2 => e2
})
res13: List[Entry] = List(Entry(0,100.0), Entry(20,120.0), Entry(30,100.0), Entry(180,0.0))
更新为简单起见,假设条目不为空。
答案 1 :(得分:3)
对于某些操作,zipped
方法的新Tuple2
方法在列表上比zip
更高效(和更懒惰)。您可以在您的基准测试中尝试这一点 - 我不知道它是否实际上更快,但它肯定可以(并且它肯定会短得多):
entries.take(1) :::
(entries,entries.drop(1)).zipped.filter(_.production != _.production)._2
它不是一对一对地压缩列表,而是创建一个列表视图,可以将各个部分一起操作,然后返回操作列表。请注意使用take和drop来处理空案例。
它不是超级高效的,因为当你真的只需要一个列表时它会构建两个列表,但它是一类尚未出现的解决方案。
答案 2 :(得分:0)
使用map [Double,Int],而不是为每个项目(即O(n ^ 2)或zipping(内存中的n ^ 2)查找重复项。然后只需添加“生产”作为键,“分钟”作为值。该地图将确保“生产”的唯一值。您可以自然地在代码中的其他位置加载地图,但即使您必须从上面的列表开始,加载地图在列表上是线性的,在地图上只有O(n log(n))。
当你添加“mymap + = production - > minute”时,地图将被替换,以便保留第一个值,在插入或使用'contains(key)'后卫之前反转列表。检查将是O(log(n)),因此整个算法将为O(n log(n))。
顺便说一句,您可以使用地图[Double,Entry]从生产值直接映射到Entry结构。然后,如果需要,您可以直接从地图中拉出地图的值并对条目的任一元素进行排序(如果需要),轻松获取列表。