【问题标题】:Scala best way to find pairs in a collection [duplicate]Scala在集合中查找对的最佳方法[重复]
【发布时间】:2018-05-26 13:49:00
【问题描述】:

我正在尝试找到在 Scala 集合中查找对的最佳方法。例如,

val list = List(1,2,3)

应该产生这些对

(1,2) (1,3) (2,1) (2,3) (3,1) (3,2)

我目前的工具似乎相当昂贵。我该如何进一步优化呢?

val pairs = list.flatMap { currentElement =>
      val clonedList: mutable.ListBuffer[Int] = list.to[ListBuffer]
      val currentIndex = list.indexOf(currentElement)
      val removedValue = clonedList.remove(currentIndex)

      clonedList.map { y =>
        (currentElement, y)
      }
    }

【问题讨论】:

  • 当您说“优化”时,您希望它优化什么?比如CPU和内存哪个更重要?另一个问题是源列表的典型大小是多少? (是几十个元素?几千个?几百万个?)
  • 重复项呢? (1, 1, 2) 应该产生什么?
  • @Brian 该解决方案会产生重复项:(1,1)
  • @Tom 我们必须忽略重复项,以便当前元素不与自身配对

标签: algorithm scala collections


【解决方案1】:
val l = Array(1,2,3,4)
val result = scala.collection.mutable.HashSet[(Int, Int)]()
for(i <- 0 until l.size) {
    for(j<- (i+1) until l.size) {
        result += l(i)->l(j)
        result += l(j)->l(i)
    }
}

这里有几个优化。首先,使用第二个循环,我们只从当前元素遍历列表到末尾,将迭代次数除以 2。然后我们将对象创建的数量限制到最少(仅创建元组并将其添加到可变哈希集中)。最后,使用哈希集,您可以免费处理重复项。另一个优化是检查集合是否已经包含元组,以避免创建一个对象。

对于 1,000 个元素,在我的笔记本电脑上花费不到 1 秒。 7s 代表 10k 个不同的元素。

注意递归,你可以这样做:

def combi(s : Seq[Int]) : Seq[(Int, Int)] = 
    if(s.isEmpty)
         Seq()
    else
        s.tail.flatMap(x=> Seq(s.head -> x, x -> s.head)) ++ combi(s.tail)

1000 个元素需要 1s 多一点。

【讨论】:

  • 这不会产生预期的结果。 scala.collection.mutable.HashSet[(Int, Int)] = Set((3,0), (1,2), (0,3), (0,2), (3,1), (2, 0), (1,0), (2,1), (0,1), (1,3), (3,2), (2,3))
  • 没错,我返回的是索引而不是列表中的相应元素。我做了一个小的修改来纠正它。
  • 我正在尝试为这个问题找出一个递归解决方案,而不是 O(n^2) 复杂度
  • 我添加了一个递归版本,但复杂度仍然是 O(n^2)。请注意,由于输出的大小是输入大小的 O(n^2),所以你不能比 O(n^2) 的复杂度做得更好......
  • 你的递归版本不是尾递归的。
【解决方案2】:

假设可以区别对待“最佳方式”(例如,大多数时候我将其视为让我自己更有效率的方式),我建议采用以下方法:

val originalList = (1 to 1000) toStream
def orderedPairs[T](list: Stream[T]) = list.combinations(2).map( p => (p(0), p(1)) ).toStream
val pairs = orderedPairs(originalList) ++ orderedPairs(originalList.reverse)
println(pairs.slice(0, 1000).toList)

【讨论】:

  • 每次使用 map 或 toList 或类似的东西时,都会复制整个列表。顺便说一句,“++”也是如此。对于 n=1000,这种方法在我的笔记本电脑上已经花费了 8 秒。
  • 我做了一些小的调整,应该可以解决上面提到的性能问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-21
  • 2016-02-11
  • 1970-01-01
  • 2019-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多