在 Java 8 流 API 中按计数分组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25441088/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 00:24:31  来源:igfitidea点击:

Group by counting in Java 8 stream API

javafunctional-programmingjava-8

提问by Muhammad Hewedy

I try to find a simple way in Java 8 stream API to do the grouping, I come out with this complex way!

我尝试在 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]));

I appreciate your input.

我感谢您的意见。

采纳答案by Jon Skeet

I think you're just looking for the overloadwhich takes another Collectorto specify what to do with each group... and then Collectors.counting()to do the counting:

我认为你只是在寻找需要另一个来指定每个组做什么的重载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);
    }
}

Result:

结果:

{Hello=2, World=1}

(There's also the possibility of using groupingByConcurrentfor more efficiency. Something to bear in mind for your real code, if it would be safe in your context.)

(还有可能groupingByConcurrent用于提高效率。如果在您的上下文中是安全的,请记住您的真实代码。)

回答by Sivakumar

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));
collect.entrySet()
       .forEach(e -> System.out.println(e.getKey() + " - " + e.getValue().size()));

回答by user_3380739

Here is the simple solution by StreamEx

这是StreamEx的简单解决方案

StreamEx.of(list).groupingBy(Function.identity(), Collectors.countingInt());

Reduce the boilerplate code: collect(Collectors.

减少样板代码: collect(Collectors.

回答by fjkjava

Here is example for list of Objects

这是对象列表的示例

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

回答by Ousmane D.

Here are slightly different options to accomplish the task at hand.

以下是完成手头任务的略有不同的选项。

using toMap:

使用toMap

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

using Map::merge:

使用Map::merge

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

回答by Donald Raab

If you're open to using a third-party library, you can use the Collectors2class in Eclipse Collectionsto convert the Listto a Bagusing a Stream. A Bagis a data structure that is built for counting.

如果你打开使用第三方库,你可以使用Collectors2的Eclipse收藏到转换ListBag使用Stream。ABag为计数构建的数据结构。

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

Output:

输出:

{World=1, Hello=2}

In this particular case, you can simply collectthe Listdirectly into a Bag.

在这种特殊情况下,你可以简单的collectList直接进入Bag

Bag<String> counted = 
        list.stream().collect(Collectors2.toBag());

You can also create the Bagwithout using a Streamby adapting the Listwith the Eclipse Collections protocols.

您还可以创建Bag不使用Stream通过调整List与Eclipse集合协议。

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

or in this particular case:

或者在这种特殊情况下:

Bag<String> counted = Lists.adapt(list).toBag();

You could also just create the Bag directly.

您也可以直接创建 Bag。

Bag<String> counted = Bags.mutable.with("Hello", "Hello", "World");

A Bag<String>is like a Map<String, Integer>in that it internally keeps track of keys and their counts. But, if you ask a Mapfor a key it doesn't contain, it will return null. If you ask a Bagfor a key it doesn't contain using occurrencesOf, it will return 0.

ABag<String>类似于 a Map<String, Integer>,因为它在内部跟踪键及其计数。但是,如果您向 a 请求Map它不包含的密钥,它将返回null。如果您向 a 请求Bag它不包含 using 的密钥occurrencesOf,它将返回 0。

Note:I am a committer for Eclipse Collections.

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