转换列表< MyObject> to Map< String,List< String>>在Java 8中,当我们有重复元素和自定义过滤条件时 [英] Converting List<MyObject> to Map<String, List<String>> in Java 8 when we have duplicate elements and custom filter criteria

查看:76
本文介绍了转换列表< MyObject> to Map< String,List< String>>在Java 8中,当我们有重复元素和自定义过滤条件时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Student class的实例。

I have an instances of Student class.

class Student {
    String name;
    String addr;
    String type;

    public Student(String name, String addr, String type) {
        super();
        this.name = name;
        this.addr = addr;
        this.type = type;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", addr=" + addr + "]";
    }

    public String getName() {
        return name;
    }

    public String getAddr() {
        return addr;
    }
}

我有一个代码来创建地图,其中它将学生姓名存储为密钥,并将一些已处理的 addr 值存储(一个List,因为我们有多个 addr 同一学生的值)与

And I have a code to create a map , where it store the student name as the key and some processed addr values (a List since we have multiple addr values for the same student) as the value.

public class FilterId {

public static String getNum(String s) {
    // should do some complex stuff, just for testing
    return s.split(" ")[1];
}

public static void main(String[] args) {
    List<Student> list = new ArrayList<Student>();
    list.add(new Student("a", "test 1", "type 1"));
    list.add(new Student("a", "test 1", "type 2"));
    list.add(new Student("b", "test 1", "type 1"));
    list.add(new Student("c", "test 1", "type 1"));
    list.add(new Student("b", "test 1", "type 1"));
    list.add(new Student("a", "test 1", "type 1"));
    list.add(new Student("c", "test 3", "type 2"));
    list.add(new Student("a", "test 2", "type 1"));
    list.add(new Student("b", "test 2", "type 1"));
    list.add(new Student("a", "test 3", "type 1"));
    Map<String, List<String>> map = new HashMap<>();

    // This will create a Map with Student names (distinct) and the test numbers (distinct List of tests numbers) associated with them.
    for (Student student : list) {
        if (map.containsKey(student.getName())) {
            List<String> numList = map.get(student.getName());
            String value = getNum(student.getAddr());

            if (!numList.contains(value)) {
                numList.add(value);
                map.put(student.getName(), numList);
            }
        } else {
            map.put(student.getName(), new ArrayList<>(Arrays.asList(getNum(student.getAddr()))));
        }
    }

    System.out.println(map.toString());

}
}

输出为:
{a = [1,2,3],b = [1,2],c = [1,3]}

如何以更优雅的方式在java8中执行相同的操作,可能正在使用流?

How can I just do the same in java8 in a much more elegant way, may be using the streams ?

找到这个 Collectors.toMap 在java 8中但是找不到一种方法来实际做同样的事情。

Found this Collectors.toMap in java 8 but could't find a way to actually do the same with this.

我试图将这些元素映射为CSV但是因为我不能这样做所以它不起作用找出一种方法可以轻松删除重复项,输出不是我目前所需要的。

I was trying to map the elements as CSVs but that it didn't work since I couldn't figure out a way to remove the duplicates easily and the output is not what I need at the moment.

Map<String, String> map2 = new HashMap<>();
map2 = list.stream().collect(Collectors.toMap(Student::getName, Student::getAddr, (a, b) -> a + " , " + b));
System.out.println(map2.toString());
// {a=test 1 , test 1 , test 1 , test 2 , test 3, b=test 1 , test 1 , test 2, c=test 1 , test 3}


推荐答案

使用流,您可以使用 Collectors.groupingBy 以及 Collectors.mapping

With streams, you could use Collectors.groupingBy along with Collectors.mapping:

Map<String, Set<String>> map = list.stream()
    .collect(Collectors.groupingBy(
        Student::getName,
        Collectors.mapping(student -> getNum(student.getAddr()),
            Collectors.toSet())));

我选择创建集合而不是列表地图,因为它似乎你不希望列表中有重复项。

I've chosen to create a map of sets instead of a map of lists, as it seems that you don't want duplicates in the lists.

如果你确实需要列表而不是集合,那么首先更有效率收集到集合,然后将集合转换为列表:

If you do need lists instead of sets, it's more efficient to first collect to sets and then convert the sets to lists:

Map<String, List<String>> map = list.stream()
    .collect(Collectors.groupingBy(
        Student::getName,
        Collectors.mapping(s -> getNum(s.getAddr()),
            Collectors.collectingAndThen(Collectors.toSet(), ArrayList::new))));

这使用 Collectors.collectingAndThen ,首先收集然后转换结果。

This uses Collectors.collectingAndThen, which first collects and then transforms the result.

另一种更紧凑的方式,没有流:

Another more compact way, without streams:

Map<String, Set<String>> map = new HashMap<>(); // or LinkedHashMap
list.forEach(s -> 
    map.computeIfAbsent(s.getName(), k -> new HashSet<>()) // or LinkedHashSet
        .add(getNum(s.getAddr())));

此变体使用 Iterable.forEach 迭代列表和 Map.computeIfAbsent 按学生名称对转换后的地址进行分组。

This variant uses Iterable.forEach to iterate the list and Map.computeIfAbsent to group transformed addresses by student name.

这篇关于转换列表&lt; MyObject&gt; to Map&lt; String,List&lt; String&gt;&gt;在Java 8中,当我们有重复元素和自定义过滤条件时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆