简体   繁体   中英

Convert List<V> in Map<K,V> with stream Java 8

I have a these model classes:

public class Student extends Person;

public class Professor extends Person;

public class University {
    private long id;
    private String name;
    private List<Person> employers;
....
}

I have a List of University and I want to convert it into a Map; Person is an abstract class and has implemented hashCode and equals method. This is an implementation with a for iteration:

Map<Person, University> mapList = new HashMap<Person, University>();
for (University u : universities) {
    for (Person p : u.getEmployers()) {
       mapList.put(p,u);
    }
}
mapList.forEach((k,v) -> System.out.println(k.toString() + v.getName()));

I am not so familiar with Java 8 stream, but how can I covert this code with lambda expression?

The other answers might be literally the same as your Java 7 version, and in this case with the built-in stream stuff it might be more succinct to use the forEach approach, but I'd like to show how to do with with purely FP style operations so that you can expand your comfort with streams.

You can use lambdas, but you don't need to for most functions as you can use Method references:

universities.stream()
// create maps for each university
    .map(u -> u.getEmployer().stream()
                .collect(Collectors.toMap(Function.identity(), p -> u))
// You need the entry set to turn back into a stream
    .map(Map::entrySet)
// flatten the entry sets into a single stream
    .flatMap(Set::stream)
// finally collect into the final map
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))

This could be simplified if you have a library with Tuples as you could skip the intermediate maps. You can also use the buil-in implementations of Map.Entry, but I find them much too verbose to be worth it.

Streams can be cleaner and more readable if you static import stuff like toMap, toList, etc.

我会这样:

universities.stream().forEach((uni) -> uni.getEmployers().stream().forEach((p) -> mapList.put(p, uni)));

I have probably not the best solution, so I would stick with java 7 approach. But here is my solution with Stream API

    Map<Person, University> mapList = universities.stream()
            .flatMap(university -> university.getEmployers().stream()
                    .map(employer -> new Tuple<>(employer, university)))
            .collect(Collectors.toMap(Tuple::getV1, Tuple::getV2));

You also need for this approach some kind of holder class

class Tuple<T, V> {
    private final T v1;
    private final V v2;

    public Tuple(T v1, V v2) {
        this.v1 = v1;
        this.v2 = v2;
    }

    public T getV1() {
        return v1;
    }

    public V getV2() {
        return v2;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM