如何根据另一种不同类型选择集合元素?

时间:2014-12-29 07:00:26

标签: scala

我知道我可以这样做:

scala> val a = List(1,2,3)
a: List[Int] = List(1, 2, 3)

scala> val b = List(2,4)
b: List[Int] = List(2, 4)

scala> a.filterNot(b.toSet)
res0: List[Int] = List(1, 3)

但是我想根据整数键选择集合的元素,如下所示:

case class N (p: Int , q: Int)
val x = List(N(1,100), N(2,200), N(3,300))
val y = List(2,4)
val z = .... ?
Z // want Z to be ((N1,100), (N3,300)) after removing the items of type N with 'p' 
  // matching any item in list y.

我知道有一种方法可以做到以下几点使得上面破解的代码工作:

val z = x.filterNot(e => y.contains(e.p))

但这看起来非常低效。还有更好的方法吗?

2 个答案:

答案 0 :(得分:4)

只做

val z = y.toSet
x.filterNot {z.contains(_.p)}

那是线性的。

答案 1 :(得分:2)

contains的问题在于搜索将是线性搜索,您正在查看O(N^2)解决方案(如果数据集不大,仍然可以)

无论如何,一个简单的解决方案是使用二进制搜索来获得O(NlnN)解决方案。您可以轻松地从列表中将val y转换为Array,然后使用java的二进制搜索方法。

scala> case class N(p: Int, q: Int)
defined class N

scala>   val x = List(N(1, 100), N(2, 200), N(3, 300))
x: List[N] = List(N(1,100), N(2,200), N(3,300))

scala>  val y = Array(2, 4) // Using Array directly.
y: Array[Int] = Array(2, 4)

scala> val z = x.filterNot(e => java.util.Arrays.binarySearch(y, e.p) >= 0)
z: List[N] = List(N(1,100), N(3,300))