以下是我的列表,其中包含列名:country,gender&年龄。
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很好,除非它弄乱了我的输出。
答案 0 :(得分:2)
没有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))
答案 1 :(得分:1)
不确定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
}
}
然后您按如下方式调用它:
// bucket by the first function, filter by the second one
items.filterGroups(tuple => (tuple._1, tuple._3))(_.length > 1)
并且,如上所述,取回所需的项目列表:
List((australia,M,35), (australia,F,35))
替代解决方案的唯一主要优势是输出类型与输入相同,而使用groupBy
强制您的结果类型为Iterable[(String, String, Int)]
。不确定你是否可能通过弄乱输出来表示这一点。
最后一点说明:在测量尺寸时,您可能不想使用列表,因为它的复杂性是线性的。我的解决方案和使用groupBy
的解决方案都使用相同类型的原始集合的构建器,因此您可能希望使用Vector
或其他集合与 O(1)用于计算length
。
但是正确的答案可能就是使用groupBy
,这对任何其他Scala开发人员来说都比较简单明了(尽管您可能也希望在迭代中使用惰性视图防止对数据进行不必要的双重传递。)