2017-02-03 11 views
0

リスト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のためには、リストのサイズを追加するために使用することができるように、リストのパラメータに名前を付けるためにどのような方法があります私が行ったのと同じようにoption 1 ys.sizeを使用していますか?

- >option 1の場合、toSeqへの最後の呼び出しを避けてリストを返す方法はありますか?

- > 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の回答に基づいて)

:オプション1の場合

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) 
+0

最後に 'toSeq'を呼び出して' List'を返すのを避けるのはどういう意味ですか?それ以外に何を返すべきですか? –

+0

1)の収集コールは、(1→3)、(4→4)などのリストを呼び出して印刷するとわかるマップを生成します。実際のリストを印刷する場合はtoSeqが必要です。要素を介して再びループすることによってコレクションを作成しています。私は実際にはペア(x、ys.size)を生成しているので、これは自動的にシーケンスに変換されると思いますが、代わりにマップを保持するので、これを避ける方法があるかどうか疑問に思っています。 – Fabio

答えて

1

は リターンaにtoSeqする最後の呼び出しを避けるためにどのような方法がありますリスト?

collectあなたがbreakOutを使用することができます希望のタイプのものにそれを割り当てるので、もし、CanBuildFromをとります。

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

collectBuilderを使用して、(ちょうどmapのような)新しいコレクションを作成します。通常、戻り値の型は原点型によって決まります。 breakOutでは、基本的には元の型を無視し、結果の型のビルダーを探します。したがって、collectが結果のコレクションを作成すると、すでに「正しい」タイプが作成されます。その結果を再度トラバースする必要はありません。オプション2の場合

、 は私がys.sizeを使用してオプション1 に行ったようリストのサイズを追加するために使用することができるように、リストのパラメータに名前を付ける方法はありますか?

はい、あなたは@

3つの選択肢の一つは、より効率的である
val dups: List[(Int,Int)] = 
    dup 
    .groupBy(identity) 
    .collect({ case (x, ys @ List(_, _, _*)) => (x, ys.size) })(breakOut) 

でそれを変数にバインドすることができますか?

dup.countを一致させて呼び出すと、dupが再び横断される必要があるため、非効率的と思われます。

Guard(lengthCompare(1)> 0の場合)はList(,、_ *)パターンよりも数サイクル遅くなりますが、測定していないと思います。そして計画していない。

免責事項:私は今考えることができない完全に異なる(より効率的な)方法があるかもしれません。私はあなたの特定の質問に答えるだけです。

+0

私の質問を編集して、最良の選択肢が何であるかを反映させてください。最後にbreakOutオプションに関するコメントを追加してください。私はこれが私の場合リスト[(Int、Int)]に必要なコレクションを余分な労力をかけずに生成するようにコレクション内で動作すると信じています。 lengthCompare(この場合はリストに少なくとも1つしかないことをチェックするので非常に効率的です)と少なくとも2つの要素があることをチェックするリストの適用解除の間にはパフォーマンスの違いがあるかどうかはまだ分かりません。 – Fabio

+0

ビットを編集して、breakOutに関する情報を追加します。長さの良いポイントコンパイル、私は怠惰/習慣からサイズを使用しました。特に一般的なケースでは、あらゆる種類のコレクションで動作させたい場合は、lengthCompareがおそらく良いでしょう。 – lutzh