我有ListBuffer[List[String]]
。我想在列表中找到共同的元素。
示例输入:
ListBuffer[List["a", "b", "c", "d"], List["a", "c", "e", "f"], List["a", "c", "g"]]
输出:
List["a", "c"]
我正在执行以下操作,但它效率不高,需要时间来处理更大的列表。
val _length = _listBuffer.length
val _flattenList = _listBuffer.flatten
val _commonValues = _flattenList.groupBy(identity).mapValues(_.size)
.filter({ case (x, y) => y == _length })
.keys
答案 0 :(得分:5)
要解决的一种方法是将缩减应用于ListBuffer
,与缓冲区内的列表相交:
val buffer = ListBuffer(List("a", "b", "c", "d"), List("a", "c", "e", "f"), List("a", "c", "g"))
val result = buffer.reduce{ _.intersect(_) }
println(result)
// List(a, c)
答案 1 :(得分:3)
由于您正在处理序列,因此该操作必然具有与每个嵌套列表中各个项的总和成比例的复杂性(在最坏的情况下)。
但是,当您到达目前为止探索的项目的常见元素为空的点时,您可以提前终止:
import scala.collection.mutable
import scala.annotation.tailrec
val buffer = mutable.ListBuffer(List("a", "b", "c", "d"),
List("a", "c", "e", "f"),
List("a", "c", "g"))
def dups[X](xss: Seq[Seq[X]]): Seq[X] = {
@tailrec
def loop(xss: Seq[Seq[X]], dup: Set[X]): Seq[X] =
xss match {
case _ if dup.isEmpty || xss.isEmpty => dup.toSeq
case head +: tail => loop(tail, dup intersect head.toSet)
}
if (xss.isEmpty) return Seq.empty[X]
else loop(xss.tail, xss.head.toSet)
}
println(dups(buffer))
您可以使用此代码on Scastie。
您可以通过重写逻辑来处理迭代器并尝试向其提供无限迭代器来验证此属性:
import scala.collection.mutable
import scala.annotation.tailrec
val buffer = mutable.ListBuffer(List("a", "b", "c", "d"),
List("a", "c", "e", "f"),
List("a", "c", "g"))
def dups[X](xss: Iterator[Seq[X]]): Seq[X] = {
@tailrec
def loop(dup: Seq[X], xss: Iterator[Seq[X]]): Seq[X] =
if (dup.isEmpty || !xss.hasNext) dup
else loop(dup intersect xss.next, xss)
if (!xss.hasNext) return Seq.empty[X]
else loop(Seq(xss.next: _*), xss)
}
println(dups(buffer.iterator))
println(dups(buffer.iterator ++ Iterator.single(Seq()) ++ Iterator.continually(Seq("a", "c"))))
您也可以使用此代码on Scastie。
两个实现都是堆栈安全的(由编译器通过@tailrec
注释进行静态检查)。
最糟糕的情况仍然具有相同的复杂性。
根据您的数据,您可能愿意使用其他方法。如果您愿意为某些空间复杂度交换一些时间复杂度,您可以复制Set
和import scala.collection.mutable
val buffer = mutable.ListBuffer(List("a", "b", "c", "d"),
List("a", "c", "e", "f"),
List("a", "c", "g"))
def dups[X](xss: Seq[Seq[X]]): Seq[X] =
xss.view.map(_.toSet).reduceOption(_ intersect _).getOrElse(Set.empty[X]).toSeq
println(dups(buffer))
,这是重复数据删除的理想选择:
Set
第三个例子也可用on Scastie。
时间方面,这种方法在某些情况下可以更好地工作,但代价是内存使用(因为我们将您的项目复制到不同的数据结构)。当然,你应该根据手头的问题来衡量和调整你的选择。
作为最后一个示例,您可以同时使用这两种方法(如果您通过使用import scala.collection.mutable
import scala.annotation.tailrec
val buffer = mutable.ListBuffer(List("a", "b", "c", "d"),
List("a", "c", "e", "f"),
List("a", "c", "g"))
def dups[X](xss: Seq[Seq[X]]): Seq[X] = {
@tailrec
def loop(xss: Seq[Seq[X]], dup: Set[X]): Seq[X] =
xss match {
case _ if dup.isEmpty || xss.isEmpty => dup.toSeq
case head +: tail => loop(tail, dup intersect head.toSet)
}
if (xss.isEmpty) return Seq.empty[X]
else loop(xss.tail, xss.head.toSet)
}
println(dups(buffer))
来查看用例的实际改进),如下面的代码段(通常情况下,可用{{ 3}}):
(4+ i 7) - (2+ i 3).