Java 流从对象列表生成地图

Java Stream Generate Map from List of Objects

我有一个class这样的。

public class Foo {
    private String prefix;
    private String sector;
    private int count;
}

给定一个 foo 列表:

//Args: prefix, sector, count
fooList.add(new Foo("44",,"RowC", 1 ));
fooList.add(new Foo("1",,"Rowa", 1 ));
fooList.add(new Foo("1",,"RowB", 1 ));
fooList.add(new Foo("1",,"Rowa", 1 ));

我需要 return 请求一个对象 按前缀 asc 排序,如下所示:

{
  "1": {
    "Rowa": "2",
    "RowB": "1"
  },
  "44": {
    "RowC": "1"
  }
}

所以问题是: 我必须按前缀对列表进行分组,然后显示每个扇区以及列表中具有相同行和扇区的项目的计数 (*)。 我得到的结果是像这样使用流:

fooList.stream()
       .collect(Collectors.groupingBy(
                Foo::getPrefix,
                Collectors.groupingBy(
                        Foo::getSector,
                        Collectors.mapping(Foo::getSector , Collectors.counting())
                )
        ));

问题是,上面的代码是计数是一个长整数,我需要 return 作为一个字符串。 我试过 .toString 但它给了我一个错误(可以将 java.lang.String 分配给 java.util.stream.Collector)。

更新

在 Andreas 和 Naman 的帮助下,现在我可以将计数映射为字符串。 我只需要按前缀排序。

谁能帮帮我?

你快到了,只需将 Collectors.mapping 行替换为:

Collectors.summingInt(Foo::getCount))

如:

List<Foo> fooList = new ArrayList<>();
fooList.add(new Foo("44", "RowC", 1 ));
fooList.add(new Foo("1", "Rowa", 1 ));
fooList.add(new Foo("1", "RowB", 1 ));
fooList.add(new Foo("1", "Rowa", 1 ));

Map<String, Map<String, String>> result = fooList.stream().collect(
        Collectors.groupingBy(
                Foo::getPrefix,
                TreeMap::new, // remove if prefix sorting not needed
                Collectors.groupingBy(
                        Foo::getSector,
                        () -> new TreeMap<>(Collator.getInstance()), // remove if sector sorting not needed
                        Collectors.collectingAndThen(
                                Collectors.summingInt(Foo::getCount),
                                String::valueOf
                        )
                )
        )
);

System.out.println(result); // prints: {1={Rowa=2, RowB=1}, 44={RowC=1}}

请注意添加到 groupingBy() 调用的 TreeMap 构造函数,这确保了映射已排序。第一种是 词典排序 ,而第二种是根据口语排序,即大小写不影响顺序。

这是你需要的吗?

代码:

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.summingInt;

public class Main {
    public static void main(String [] args){
        List<Foo> fooList = new ArrayList<>();
        fooList.add(new Foo("44", "RowC", 1 ));
        fooList.add(new Foo("1", "Rowa", 1 ));
        fooList.add(new Foo("1", "RowB", 1 ));
        fooList.add(new Foo("1", "Rowa", 1 ));

        Map<String, Map<String, Integer>> result = grouper(fooList);
        result.forEach( (k,v) -> System.out.printf("%s\n%s\n", k,v) );
    }

    /* group the list by the prefix, and then show, every sector and the
    *  count(*) of items on the list with the same row and sector.*/
    public static Map<String, Map<String, Integer>> grouper(List<Foo> foos){
        //Map<prefix, Map<sector, count>
        Map<String, Map<String, Integer>> result = foos.stream()
                .collect(
                        //Step 1 - group by prefix. Outer map key is prefix.
                        groupingBy( Foo::getPrefix,
                                //Use a tree map which wil be sorted by its key, i.e prefix.
                                TreeMap::new,
                                //Step 2 - group by sector.
                                groupingBy( Foo::getSector,
                                        //Step 3 - Sum the Foo's in each sector in each prefix.
                                        summingInt(Foo::getCount)
                                )
                        )
                );
        return result;
    }

}

输出:

1
{Rowa=2, RowB=1}
44
{RowC=1}

PS - 我提到了 this tutorial to answer your question. I referred to the examples in "2.5. Grouping by Multiple Fields" and "2.7. Getting the Sum from Grouped Results". The next step was to find out how to also order by the key of a map while grouping which I got from "2.11. Modifying the Return Map Type" and also checked it here.