2017-05-30 118 views
4

我正在使用java 8的计数收集器来获取有关计数值的信息。Java8计数收集器附加信息

对于ex; 如果我有一个像

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); 

我能够做

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

这导致结构

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

数在一个文档中每个单词的出现一堆流但是,我想让这个计数与它所源自的docId相关联。例如,我想有一个结构

[ 
{a=(randId1, 1), b=(randId1, 2), c=(randId1, 2)}, 
{b=(randId2, 1), c=(randId2, 1), d=(randId2, 1)} 
] 

其中randId1randId2可以在运行时产生的(I只需要一种方法来追溯到唯一的源)和()表示Apache的一个Pair类。

我试图来包装的一个(docId, doc)Pair DOC但我被困在修改Collectors.counting()替代

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()); 

如何获得所需要的格式输出?

回答

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复制您的代码段和适应你的最后一个一般的参数LongPair

   // 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代替了Pair,因为它做了同样的事情,我已经在我的类路径中拥有了它。

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方法参考。