假设我有一个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
as
由x
的{{1}}或y
与a
例如:
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))
)
答案 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)。