Scala收集功能

时间:2017-02-03 16:46:13

标签: scala

假设我想用duplicates列表中打印count。所以我有3 options,如下所示:

  def dups(dup:List[Int]) = {
     //1)
     println(dup.groupBy(identity).collect { case (x,ys) if ys.lengthCompare(1) > 0 => (x,ys.size) }.toSeq)
     //2)
     println(dup.groupBy(identity).collect { case (x, List(_, _, _*)) => x }.map(x => (x, dup.count(y => x == y))))
    //3)
     println(dup.distinct.map((a:Int) => (a, dup.count((b:Int) => a == b )) ).filter( (pair: (Int,Int) ) => { pair._2 > 1 } ))

  }

问题:

- >对于option 2,有没有办法命名list参数,以便它可以用来附加列表的大小,就像我在option 1中使用ys.size一样?

- >对于option 1,有没有办法避免最后一次调用toSeq返回List?

- > 3个选项中的哪一个是more efficient by using the least amount of loops

作为示例输入:列表(1,1,1,2,3,4,5,5,6,100,101,101,102) 应打印:列表((1,3),(5,2),(101,2))

根据下面的@lutzh答案,最好的方法是执行以下操作:

val list: List[(Int, Int)] = dup.groupBy(identity).collect({ case (x, ys @ List(_, _, _*)) => (x, ys.size) })(breakOut)
 val list2: List[(Int, Int)] = dup.groupBy(identity).collect { case (x, ys) if ys.lengthCompare(1) > 0 => (x, ys.size) }(breakOut)

1 个答案:

答案 0 :(得分:1)

  

对于选项1,有什么方法可以避免最后一次调用toSeq   返回一个List?

collect需要CanBuildFrom,因此,如果您将其指定为所需类型的内容,则可以使用breakOut

import collection.breakOut
val dups: List[(Int,Int)] = 
    dup
    .groupBy(identity)
    .collect({ case (x,ys) if ys.size > 1 => (x,ys.size)} )(breakOut)

collect将使用map创建一个新集合(就像Builder)。通常返回类型由原点类型确定。使用breakOut,您基本上忽略原始类型并查找结果类型的构建器。因此,当collect创建生成的集合时,它已经创建了"权利"类型,您不必再次遍历结果进行转换。

  

对于选项2,有没有办法命名list参数以便它   可以用来附加列表的大小,就像我在选项1中所做的那样   使用ys.size?

是的,您可以使用@

将其绑定到变量
val dups: List[(Int,Int)] = 
    dup
    .groupBy(identity)
    .collect({ case (x, ys @ List(_, _, _*)) => (x, ys.size) } )(breakOut)
  

3个选项中哪一个更有效?

在匹配上调用dup.count似乎效率低下,因为需要再次遍历dup,我会避免这种情况。

我的猜测是守卫(如果lengthCompare(1)> 0)比List(,_ *)模式少几个周期,但我还没有测量。而且我不打算。

免责声明:可能存在一种完全不同(且更有效)的方式,我现在无法想到。我只回答你的具体问题。