2017-05-30 6 views
4

私は値の数に関する情報を得るためにJava 8の集計を使用しています。追加情報付きのJava8集計コレクタ

例: 私はこれが

[ 
{a=1, b=2, c=2}, 
{b=1, c=1, d=1} 
] 

ような構造になり

List<Map<String, Long>> collect = docs 
    .map(doc -> doc.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))) 
    .collect(Collectors.toList()); 

を行うことによって、ドキュメント内の各単語の出現をカウントすることができる午前

Stream<String> doc1 = Stream.of("a", "b", "c", "b", "c"); 
Stream<String> doc2 = Stream.of("b", "c", "d"); 
Stream<Stream<String>> docs = Stream.of(doc1, doc2); 

のようなストリームの束を持っている場合しかし、そのカウントを元のdocIdに関連付けることができます。たとえば、私は

[ 
{a=(randId1, 1), b=(randId1, 2), c=(randId1, 2)}, 
{b=(randId2, 1), c=(randId2, 1), d=(randId2, 1)} 
] 
randId1randId2は、実行時に生成することができます

(私は独特のソースに戻って追跡する方法が必要です)と()ような構造を持っていると思いアパッチからPairクラスを表します。

私は(docId, doc)Pairでドキュメントをラップすることを試みたが、私は私が必要なフォーマットで出力を得るにはどうすればよい

List<Map<String, Long>> collect = docs.map(doc -> Pair.of(UUID.randomUUID(), doc)) 
    .map(p -> p.getRight().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))) 
    .collect(Collectors.toList()); 

Collectors.counting()置換を修正することで立ち往生していますか?

答えて

3

これはいかがですか?

List<Map<String, Pair<UUID, Long>>> collect = docs.map(doc -> { 
    UUID id = UUID.randomUUID(); 
    return doc.collect(groupingBy(
     identity(), 
    // v--- adapting Collector<?,?,Long> to Collector<?,?,Pair>  
     collectingAndThen(counting(), n -> Pair.of(id, n)) 
    )); 
}).collect(Collectors.toList()); 

私は自分のコードスニペットをコピーして、Collectors#collectingAndThenによってPairにあなたの最後のジェネリック引数Longを適応しています:

   // v--- the code need to edit is here 
List<Map<String, Long>> collect = docs 
.map(doc -> doc.collect(Collectors.groupingBy(Function.identity() 
//     the code need to edit is here ---v 
              ,Collectors.counting()))) 
.collect(Collectors.toList()); 
+0

偉大な答え..ありがとう – Anoop

+0

@Anoop全くありません。どう致しまして。 –

5

これはあまり読みやすいものではありません。私はをAbstractMap.SimpleEntryに置き換えました。同じことをしており、すでにクラスパス上にあります。

List<Map<String, AbstractMap.SimpleEntry<Long, UUID>>> result = docs.map(doc -> doc.collect(Collectors.collectingAndThen(
      Collectors.groupingBy(Function.identity(), Collectors.counting()), 
      map -> { 
       UUID rand = UUID.randomUUID(); 
       return map.entrySet().stream().collect(Collectors.toMap(
         Entry::getKey, 
         e -> new AbstractMap.SimpleEntry<>(e.getValue(), rand))); 
      }))) 
      .collect(Collectors.toList()); 

    System.out.println(result); 

そして、これの出力:

[{a=1=890d7276-efb7-41cc-bda7-f2dd2859e740, 
    b=2=890d7276-efb7-41cc-bda7-f2dd2859e740, 
    c=2=890d7276-efb7-41cc-bda7-f2dd2859e740}, 

{b=1=888d78a5-0dea-4cb2-8686-c06c784d4c66, 
    c=1=888d78a5-0dea-4cb2-8686-c06c784d4c66, 
    d=1=888d78a5-0dea-4cb2-8686-c06c784d4c66}] 
+0

ここにいくつかの偉大な答えの中でもう一つ。どうもありがとうございます。 。 – Anoop

2

私は次のようにあなたがそれを行うことができると思う:

List<Map<String, Pair<UUID, Long>>> result = docs 
    .map(doc -> Pair.of(UUID.randomUUID(), doc)) 
    .map(p -> p.getRight() // right: doc stream 
     .map(word -> Pair.of(word, p.getLeft()))) // left: uuid 
    .map(stream -> stream.collect(Collectors.toMap(
     Pair::getLeft, // word 
     p -> Pair.of(p.getRight(), 1L), // right: uuid 
     (p1, p2) -> Pair.of(p1.getLeft(), p1.getRight() + p2.getRight())))) // merge 
    .collect(Collectors.toList()); 

私は言葉の両方の周りを通過するPair.ofを複数回使用してきましたし、ランダムなドキュメントID最後に、Collectors.toMapには、キーに衝突があったときに値をマージする機能があります。結果はつまり、あなたが望むとおりにである:

[{a=(fa843dec-3e02-4811-b34f-79949340b4c5,1), 
    b=(fa843dec-3e02-4811-b34f-79949340b4c5,2), 
    c=(fa843dec-3e02-4811-b34f-79949340b4c5,2)}, 
{b=(dc2ad8c7-298a-433e-8b27-88bd3c8eaebb,1), 
    c=(dc2ad8c7-298a-433e-8b27-88bd3c8eaebb,1), 
    d=(dc2ad8c7-298a-433e-8b27-88bd3c8eaebb,1)}] 

多分これは、ヘルパーメソッドに、内部のストリームを収集し、コードを移動することによって改善することができます。

private Map<String, Pair<UUID, Long>> collectInnerDoc(
     Stream<Pair<String, UUID>> stream) { 
    return stream.collect(Collectors.toMap(
     Pair::getLeft, // word 
     p -> Pair.of(p.getRight(), 1L), // random doc id 
     (p1, p2) -> Pair.of(p1.getLeft(), p1.getRight() + p2.getRight()))); // merge 
} 

あなたは、その後に、このメソッドを使用することができますあなたの外側の流れを収集:

List<Map<String, Pair<UUID, Long>>> result = docs 
    .map(doc -> Pair.of(UUID.randomUUID(), doc)) 
    .map(p -> p.getRight() // right: doc stream 
     .map(word -> Pair.of(word, p.getLeft()))) // left: uuid 
    .map(this::collectInnerDoc) // map inner stream to map 
    .collect(Collectors.toList()); 

これは、プライベートメソッドは、あなたが、外側ストリームを収集している同じクラスで宣言されている前提としています。これが当てはまらない場合は、this::collectInnerDocsメソッドリファレンスを適宜変更してください。

関連する問題