通过计数Java 8流API进行分组

时间:2014-08-22 06:46:21

标签: java functional-programming java-8

我尝试在Java 8流API中找到一种简单的方法来进行分组,我用这种复杂的方式出来了!

List<String> list = new ArrayList<>();

list.add("Hello");
list.add("Hello");
list.add("World");

Map<String, List<String>> collect = list.stream().collect(
        Collectors.groupingBy(o -> o));
System.out.println(collect);

List<String[]> collect2 = collect
        .entrySet()
        .stream()
        .map(e -> new String[] { e.getKey(),
                String.valueOf(e.getValue().size()) })
        .collect(Collectors.toList());

collect2.forEach(o -> System.out.println(o[0] + " >> " + o[1]));

感谢您的意见。

6 个答案:

答案 0 :(得分:266)

我认为你只是在寻找overload,它需要另一个Collector指定如何处理每个群组...然后Collectors.counting()进行计数:

import java.util.*;
import java.util.stream.*;

class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        list.add("Hello");
        list.add("Hello");
        list.add("World");

        Map<String, Long> counted = list.stream()
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

        System.out.println(counted);
    }
}

结果:

{Hello=2, World=1}

(还有可能使用groupingByConcurrent来提高效率。如果在您的环境中安全,请记住您的真实代码。)

答案 1 :(得分:6)

    List<String> list = new ArrayList<>();

    list.add("Hello");
    list.add("Hello");
    list.add("World");

    Map<String, List<String>> collect = list.stream().collect(
            Collectors.groupingBy(o -> o));
    System.out.println(collect); 
    collect.entrySet().forEach(e -> System.out.println(e.getKey() + " >> " + e.getValue().size()));

答案 2 :(得分:4)

这里是对象列表的示例

Map<String, Long> requirementCountMap = requirements.stream().collect(Collectors.groupingBy(Requirement::getRequirementType, Collectors.counting()));

答案 3 :(得分:4)

完成手头任务的选择略有不同。

使用toMap

list.stream()
    .collect(Collectors.toMap(Function.identity(), e -> 1, Math::addExact));

使用Map::merge

Map<String, Integer> accumulator = new HashMap<>();
list.forEach(s -> accmulator.merge(s, 1, Math::addExact));

答案 4 :(得分:3)

以下是StreamEx

的简单解决方案
StreamEx.of(list).groupingBy(Function.identity(), Collectors.countingInt());

减少样板代码:collect(Collectors.

答案 5 :(得分:1)

如果您愿意使用第三方库,则可以使用Eclipse Collections中的Collectors2类,使用{将List转换为Bag {1}}。 Bagbuilt for counting的数据结构。

Stream

输出:

Bag<String> counted =
        list.stream().collect(Collectors2.countBy(each -> each));

Assert.assertEquals(1, counted.occurrencesOf("World"));
Assert.assertEquals(2, counted.occurrencesOf("Hello"));

System.out.println(counted.toStringOfItemToCount());

在这种情况下,您可以简单地将{World=1, Hello=2} 的{​​{1}}直接变成collect

List

您还可以通过使Bag适应Eclipse Collections协议来创建Bag<String> counted = list.stream().collect(Collectors2.toBag()); ,而无需使用Bag

Stream

或在这种情况下:

List

您也可以直接创建Bag。

Bag<String> counted = Lists.adapt(list).countBy(each -> each);

Bag<String> counted = Lists.adapt(list).toBag(); 就像Bag<String> counted = Bags.mutable.with("Hello", "Hello", "World"); ,因为它在内部跟踪键及其计数。但是,如果您向Bag<String>询问它不包含的密钥,它将返回Map<String, Integer>。如果您使用Mapnull索取一个密钥,它将返回0。

注意::我是Eclipse Collections的提交者。