Scala 从列表中获取所有重复记录,而不需要二次时间复杂度?

Scala 从列表中获取所有重复记录,而不需要二次时间复杂度?,scala,performance,time-complexity,user-defined-functions,scala-collections,Scala,Performance,Time Complexity,User Defined Functions,Scala Collections,下面是我的列表,其中包含列名:国家、性别和年龄 scala> funList res1: List[(String, String, String)] = List((india,M,15), (usa,F,25), (australia,M,35), (kenya,M,55), (russia,M,75), (china,T,95), (england,F,65), (germany,F,25), (finland,M,45), (australia,F,35)) 我的目标是找到(国家

下面是我的列表,其中包含列名:国家、性别和年龄

scala> funList
res1: List[(String, String, String)] = List((india,M,15), (usa,F,25), (australia,M,35), (kenya,M,55), (russia,M,75), (china,T,95), (england,F,65), (germany,F,25), (finland,M,45), (australia,F,35))
我的目标是找到(国家、年龄)组合的重复记录。请注意,我只想获取所有重复记录,而忽略其他记录。和列表还应包含具有重复记录的其他列值

输出应如下所示:

australia,M,35
australia,F,35
如果没有groupBy操作和n*square复杂度,那就太好了。GroupBy很好,除非它把我的输出弄乱。

没有
GroupBy()
。我不确定它的复杂性

val keys = funList.map{case (a,b,c) => (a,c)}  //isolate elements of interest
val dups = keys diff keys.distinct             //find the duplicates
funList.filter{case (a,b,c) => dups.contains((a,c))}
//res0: List[(String, String, String)] = List((australia,M,35), (australia,F,35))
没有
groupBy()
。我不确定它的复杂性

val keys = funList.map{case (a,b,c) => (a,c)}  //isolate elements of interest
val dups = keys diff keys.distinct             //find the duplicates
funList.filter{case (a,b,c) => dups.contains((a,c))}
//res0: List[(String, String, String)] = List((australia,M,35), (australia,F,35))

不确定您所说的
groupBy
可能会干扰输出是什么意思。您可以按如下方式使用它,您将得到您要查找的副本列表:

// input
val items = List(("india","M",15), ("usa","F",25), ("australia","M",35), ("kenya","M",55), ("russia","M",75), ("china","T",95), ("england","F",65), ("germany","F",25), ("finland","M",45), ("australia","F",35))

items.
  groupBy { case (nation, _, age) => nation -> age }. // group by relevant items
  filter(_._2.length > 1).                            // keep only duplicates
  flatMap(_._2)                                       // get them and flatten the result
或者您可能有兴趣使用
groupBy
作为您自己函数的基础,该函数通过一个键存储值,并通过一些谓词过滤结果,如下所示:

implicit class FilterGroups[A, CC[X] <: Iterable[X]](self: CC[A]) {
  import scala.collection.mutable
  import scala.collection.mutable.Builder
  import scala.collection.generic.CanBuildFrom
  def filterGroups[K, That](f: A => K)(p: CC[A] => Boolean)(implicit bfs: CanBuildFrom[CC[A], A, CC[A]], bf: CanBuildFrom[CC[A], A, That]): That = {
    val m = mutable.Map.empty[K, Builder[A, CC[A]]]
    for (elem <- self) {
      val key = f(elem)
      val bldr = m.getOrElseUpdate(key, bfs())
      bldr += elem
    }
    val b = bf()
    for {
      (_, v) <- m
      group = v.result if p(group)
      elem <- group
    } b += elem
    b.result
  }
}
并且,如上所述,返回所需的项目列表:

List((australia,M,35), (australia,F,35))
替代解决方案的唯一主要优点是输出类型与输入类型相同,而使用
groupBy
会强制您的结果类型为
Iterable[(String,String,Int)]
。我不确定你是不是故意把输出搞砸了

无论哪种方式,我都会说时间复杂度实际上是线性的(我们必须一次传递到bucket,一次传递到filter,但我们仍然可以去掉big-O表示法中的常量)。这当然意味着空间复杂度也与集合大小有关(因为我们将原始结果存储在bucket中)

最后一点注意:在度量大小时,您可能不希望使用列表,因为它的复杂性是线性的。我的解决方案和使用
groupBy
的解决方案都使用与原始集合相同类型的构建器,因此您可能希望使用
向量
或其他具有O(1)的集合来计算
长度


但是正确的答案可能是只使用
groupBy
,这对任何其他Scala开发人员来说都更简单、更清晰(尽管您可能还希望在迭代过程中使用惰性视图,以防止不必要的数据重复传递).

不确定您所说的
groupBy
可能会干扰输出的意思。您可以按如下方式使用它,您将得到您要查找的副本列表:

// input
val items = List(("india","M",15), ("usa","F",25), ("australia","M",35), ("kenya","M",55), ("russia","M",75), ("china","T",95), ("england","F",65), ("germany","F",25), ("finland","M",45), ("australia","F",35))

items.
  groupBy { case (nation, _, age) => nation -> age }. // group by relevant items
  filter(_._2.length > 1).                            // keep only duplicates
  flatMap(_._2)                                       // get them and flatten the result
或者您可能有兴趣使用
groupBy
作为您自己函数的基础,该函数通过一个键存储值,并通过一些谓词过滤结果,如下所示:

implicit class FilterGroups[A, CC[X] <: Iterable[X]](self: CC[A]) {
  import scala.collection.mutable
  import scala.collection.mutable.Builder
  import scala.collection.generic.CanBuildFrom
  def filterGroups[K, That](f: A => K)(p: CC[A] => Boolean)(implicit bfs: CanBuildFrom[CC[A], A, CC[A]], bf: CanBuildFrom[CC[A], A, That]): That = {
    val m = mutable.Map.empty[K, Builder[A, CC[A]]]
    for (elem <- self) {
      val key = f(elem)
      val bldr = m.getOrElseUpdate(key, bfs())
      bldr += elem
    }
    val b = bf()
    for {
      (_, v) <- m
      group = v.result if p(group)
      elem <- group
    } b += elem
    b.result
  }
}
并且,如上所述,返回所需的项目列表:

List((australia,M,35), (australia,F,35))
替代解决方案的唯一主要优点是输出类型与输入类型相同,而使用
groupBy
会强制您的结果类型为
Iterable[(String,String,Int)]
。我不确定你是不是故意把输出搞砸了

无论哪种方式,我都会说时间复杂度实际上是线性的(我们必须一次传递到bucket,一次传递到filter,但我们仍然可以去掉big-O表示法中的常量)。这当然意味着空间复杂度也与集合大小有关(因为我们将原始结果存储在bucket中)

最后一点注意:在度量大小时,您可能不希望使用列表,因为它的复杂性是线性的。我的解决方案和使用
groupBy
的解决方案都使用与原始集合相同类型的构建器,因此您可能希望使用
向量
或其他具有O(1)的集合来计算
长度


但是正确的答案可能是只使用
groupBy
,这对任何其他Scala开发人员来说都更简单、更清晰(尽管您可能还希望在迭代过程中使用惰性视图,以防止不必要的重复传递数据)。

groupBy{u==}filter{uu.count>1}
我想到了。我认为上面的groupBy操作不适用于您
xs groupBy{x=>x}filter{case(x,y)=>y.length>2}
仍然有效。不,您是按整个元组分组的,Button Monkey只希望元组中的两个项重复。
groupBy{u==}filter{uuuu.count>1}XSGroupBy{x=>x}filter{case(x,y)=>y.length>2}
虽然有效。不,你是按整个元组分组的,Button Monkey只希望元组中的两个项目重复。顺便说一句,为了测量列表的长度,有
lengthCompare
methodNice,我不知道这个。顺便说一句,为了测量列表的长度,有
lengthCompare
methodNice,我不知道这个。