如何将列表转换为这样的对列表?

时间:2017-04-16 16:25:08

标签: scala collections

假设我有一个case class A(x: Int, y: Int) val as = List(A(0, 0), A(0, 1), A(1, 0), A(1, 1)) 列表:

(A, Set[A])

我想将其转换为成对列表as,以便:

  • 对的第一个元素列表是(a, set)
  • 每对中的
  • set asx的{​​{1}}或ya

例如:

val pairs = List(
  A(0, 0) -> Set(A(0, 1), A(1, 0)),
  A(0, 1) -> Set(A(0, 0), A(1, 1)),
  A(1, 0) -> Set(A(0, 0), A(1, 1)),
  A(1, 1) -> Set(A(0, 1), A(1, 0))
)

2 个答案:

答案 0 :(得分:2)

"蛮力":

case class A(x: Int, y: Int)
val as = List(A(0, 0), A(0, 1), A(1, 0), A(1, 1))

val mappings = for {
  a1 <- as
  a2 <- as
  if (a1 != a2)
  if (a1.x == a2.x || a1.y == a2.y)
} yield a1 -> a2

val result = mappings.groupBy(_._1).mapValues(_.map(_._2))

答案 1 :(得分:1)

通过一些索引,您可以在平均情况下获得更快的速度(同时为索引支付一些额外的存储空间):

首先我们为Xs和Ys创建一个索引:

val xi = as.groupBy(_.x) // O(n) 
val yi = as.groupBy(_.y) // O(n)

然后我们进行一次传递并使用索引映射每个元素:

// This is essentially O(n^2) worst case, but it can be much less if the toSet doesn't have to go through a lot each time
val inter = for( a <- as ) yield 
   (a, (xi.get(a.x).toSet ++ yi.get(a.y).toSet).flatten)

最后,您可能希望从Set中删除与键相同的元素:

inter.map(x => (x._1, x._2 - x._1)) // O(n)

总的来说,这仍然是最坏情况O(n ^ 2),但是在索引足够稀疏的情况下,它可以基本上是O(n)。