删除冗余条目,scala方式

时间:2010-04-03 13:01:30

标签: scala

编辑:添加了以下事实:列表已排序,并且实现“重复”具有误导性,将其替换为标题中的“冗余”。

我有一个排序的条目列表,说明给定时间间隔内的生产值。在以后说明完全相同的值的条目不会添加任何信息,可以安全地省略。

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))

有何评论?我错过了一些斯卡拉魔法吗?

3 个答案:

答案 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结构。然后,如果需要,您可以直接从地图中拉出地图的值并对条目的任一元素进行排序(如果需要),轻松获取列表。