2016-08-14 16 views
4

各要素の出現回数をカウントするために次のスニペットを記述しました。はるかに短い方法でこれを達成することは可能ですか?整数配列内の各要素のJavaカウントの発生

int[] arr = {1, 6, 2, 8, 5, 4, 7, 7, 5, 7}; 
Arrays.stream(arr) 
     .collect(ArrayList::new, ArrayList::add, ArrayList::addAll) 
     .stream() 
     .collect(Collectors.groupingBy(s -> s)) 
     .forEach((k, v) -> System.out.println(k+" "+v.size())); 

また、1回以上出現する要素のみを表示したいと考えています。そこで以下のように修正してみましたが、エラーが発生しました。

.forEach((k, v) -> if(v.size() > 1) System.out.println(k+" "+v.size())); 

これを行う正しい方法は何ですか。後者の問題については

答えて

8

あなたは二Streamパイプラインに続いて最初のcollectを必要とする理由、あなたが最初の部分について

.forEach((k, v) -> {if(v.size() > 1) System.out.println(k+" "+v.size());}); 

.forEach((k, v) -> if(v.size() > 1) System.out.println(k+" "+v.size())); 

を変更する必要があり、それははっきりしていません。目的はStream<Integer>IntStreamを変換した場合 、boxed()使用:DICIが示唆したように

Arrays.stream(arr) 
     .boxed() 
     .collect(Collectors.groupingBy(s -> s)) 
     .forEach((k, v) -> System.out.println(k+" "+v.size())); 

、あなたのグループにもチェーンコレクターができ出現のその番号と各番号:

Map<Integer,Integer> occurrences = 
    Arrays.stream(arr) 
      .boxed() 
      .collect(Collectors.groupingBy(s -> s, Collectors.counting())); 
+0

すっごいです!それを考えなかった。 – DhiwaTdG

+4

'Collectors.groupingBy(Function.identity()、Collectors.counting())'を使ってより良い方法があります。静的なインポートの束では、それはより良く見える – Dici

+0

また、それを印刷する代わりにとして結果を返すことは可能ですか? – DhiwaTdG

0

I私のソリューションも共有したい!

// Solution 1 [Improved from Eran's solution & suggestion] 
int[] arr = {1, 6, 2, 8, 5, 4, 7, 7, 5, 7}; 
Map<Integer, Long> counts = Arrays.stream(arr) 
    .boxed() 
    .collect(collectingAndThen(groupingBy(n -> n, counting()), 
     map -> map.entrySet().stream() 
      .filter(n -> n.getValue() > 1) 
      .collect(toMap(Entry::getKey, Entry::getValue)) 
)); 
System.out.println(counts.toString()); 

// Solution 2 [Improved from Dici's suggestion] 
int[] arr = {1, 6, 2, 8, 5, 4, 7, 7, 5, 7}; 
Map<Object, Long> counts = Arrays.stream(arr) 
    .collect(ArrayList::new, ArrayList::add, ArrayList::addAll) 
    .stream() 
    .collect(groupingBy(Function.identity(), counting())); 
counts.values().removeIf(count -> count < 2); 
System.out.println(counts.toString()); 
+1

'groupingBy'仕​​様では、返されるマップが変更可能であるとは限りません。このようなソリューションは、将来のJava(またはOpenJDKベースではない)実装では失敗する可能性があります。 –

+1

あなたが簡単に使用することにより@Tagirで述べた問題を解決することができます '.collect(groupingBy(Function.identity()、HashMapのは::新しい、カウント()));'。次に、変更可能な 'HashMap'であることが保証され、' removeIf'を使用することができます。これは 'collectingAndThen'と一緒に働くことに注意してください。ところで、 'System.out.println'を使うときに' toString() 'は必要ありません... – Holger

3

あなたは、サードパーティのライブラリを使用することに開いている場合は、Eclipse Collectionsは次のように使用することができますBag種類があります:あなたはとしてのint [] arrの変数を維持する必要がある場合

Bags.mutable.with(1, 6, 2, 8, 5, 4, 7, 7, 5, 7) 
    .selectByOccurrences(count -> count > 1) 
    .forEachWithOccurrences((k, count) -> System.out.println(k+" "+count)); 

をint配列の場合、IntBagを使用できます。 更新:9/9/16:プリミティブBagsselectByOccurrencesを追加しました。EC 8.0 releaseで利用できます。次のコードは、collect(i -> i)を使ってint型をボックスすることなく動作するようになりました:

IntBags.mutable.with(arr) 
    .selectByOccurrences(count -> count > 1) 
    .forEachWithOccurrences((k, count) -> System.out.println(k+" "+count)); 

注:私はEclipseのコレクションのためのコミッターです。

0

は、周波数を使用して実行される可能性があります。

List<Integer> list = ImmutableList.of(1, 2, 3, 4, 5, 6, 3, 4, 5); 
Map<Integer, Integer> result = list.stream().distinct().collect(Collectors.toMap(Function.identity(), token -> Collections.frequency(list, token))); 
関連する問題