如何使scala集合包含唯一元素? (“唯一”定义)

时间:2013-04-18 12:39:56

标签: scala scala-collections

说我有一个如下列表:

val l = List( (1, 2, "hi"), (1, 3, "hello"), (2, 3, "world"), (1, 2, "hello") )

我想使l的元素明显忽略元组的第3个元素。也就是说,l的两个元素如果它们的前两个元素相同则被认为是相同的。

所以makeDistinct(l)应该返回

List( (1, 2, "hi"), (1, 3, "hello"), (2, 3, "world") )

实施makeDistinct

的最类似Scala和通用方法是什么?

编辑:我们可以自由选择要删除的内容,并且无需保留订购。

2 个答案:

答案 0 :(得分:3)

如果您想对列表执行此操作,请使用groupBy

l.groupBy(x => (x._1, x._2)).map(kv => kv._2.head).toList

如果你真的想要对所有集合类型都是通用的:

scala> import scala.collection.generic.CanBuildFrom
import scala.collection.generic.CanBuildFrom

scala> def distinct[A, B, C, CC[X] <: Traversable[X]](xs: CC[(A, B, C)])(implicit cbf: CanBuildFrom[Nothing, (A, B, C), CC[(A, B, C)]]): CC[(A, B, C)] = xs.groupBy(x => (x._1, x._2)).map(kv => kv._2.head).to[CC]
warning: there were 1 feature warnings; re-run with -feature for details
distinct: [A, B, C, CC[X] <: Traversable[X]](xs: CC[(A, B, C)])(implicit cbf: scala.collection.generic.CanBuildFrom[Nothing,(A, B, C),CC[(A, B, C)]])CC[(A, B, C)]

scala> distinct(List((1, 2, "ok"), (1, 3, "ee"), (1, 2, "notok")))
res0: List[(Int, Int, String)] = List((1,3,ee), (1,2,ok))

答案 1 :(得分:1)

您可以使用Ordering

scala> SortedSet(l: _*)(Ordering[(Int, Int)].on(x => (x._1, x._2))).toList
res33: List[(Int, Int, String)] = List((1,2,hello), (1,3,hello), (2,3,world))

唯一的问题是保留了最后找到的元素。对于第一个,您需要反转列表:

scala> SortedSet(l.reverse: _*)(Ordering[(Int, Int)].on(x => (x._1, x._2))).toList
res34: List[(Int, Int, String)] = List((1,2,hi), (1,3,hello), (2,3,world))

反过来并不是最优的,但也许可以按相反的顺序直接创建列表,这样可以避免构建不必要的中间列表。