Java:如何将对象从List <T>添加到Map(键:枚举,值List <T>)

时间:2019-06-26 15:34:28

标签: java list collections java-stream

我正在尝试将List<Farm>中的对象添加到Map<Animal, List<Farm>>

public class Farm {
    private String farmName;
    private EnumSet<Animal> animals = EnumSet.noneOf(Animal.class);
    /* ... */
}

Farm f1 = new Farm("Farm A", EnumSet.of(Animal.CAT, Animal.DOG, Animal.DUCK));
Farm f2 = new Farm("Farm B", EnumSet.of(Animal.PIG, Animal.CAT, Animal.HORSE));
Farm f3 = new Farm("Farm C", EnumSet.of(Animal.DUCK));

任务1:将对象添加到List<Farm>

List<Farm> list = new ArrayList<>();
list.add(f1);
list.add(f2);
list.add(f3);

任务2:将列表中的对象添加到地图(键:Animal,值:List <Farm>)中,我是通过以下方式完成此任务的:

Map<Animal, List<Farm>> map = new HashMap<>();

for(Farm farm: list) {
    for(Animal an: farm.getAnimals()) {
        if(!map.containsKey(an)) {
            List<Farm> new_list = new ArrayList<>();
            new_list.add(farm);
            map.put(an, new_list);
        }else {     
            List<Farm> old_list = map.get(an);
            if(!old_list.contains(farm)) {
                old_list.add(farm);
                    }
            }
        }
    }

还有第二种/更有效的解决方案吗? 像这样:

Map<Animal, List<Farm>> map = list.stream().collect(Collectors.groupingBy(Farm::getAnimals)));

这不起作用,因为getAnimals返回了EnumSet<Animal>

2 个答案:

答案 0 :(得分:3)

您可能想保留循环,但要使其现代化:

Map<Animal, List<Farm>> map = new EnumMap<>(Animal.class);
for(Farm farm: list)
    for(Animal an: farm.getAnimals())
        map.computeIfAbsent(an, x -> new ArrayList<>()).add(farm);

在循环中,add(farm)冗余地出现在两个分支中,因为您始终将其添加到List中。然后,computeIfAbsent允许消除条件,因为它将返回现有值或构造新值,然后放入并返回。 groupingBy收集器也在内部使用此方法。

对它使用Stream操作有一个缺点,即您需要两个值的临时持有人,例如

Map<Animal, List<Farm>> map = list.stream()
    .flatMap(farm -> farm.getAnimals().stream()
        .map(animal -> new AbstractMap.SimpleImmutableEntry<>(animal, farm)))
    .collect(Collectors.groupingBy(Map.Entry::getKey,
        () -> new EnumMap<>(Animal.class),
        Collectors.mapping(Map.Entry::getValue, Collectors.toList())));

答案 1 :(得分:0)

我从相反的方向开始,但是我认为这很有帮助

    Map<Animal, List<Farm>> map = Arrays.stream(Animal.values())
            .collect(Collectors.toMap(an -> an, an -> list.stream().filter(f -> f.getAnimals().contains(an)).collect(Collectors.toList())));

在没有任何一个农场包含动物的情况下,该动物可能有空集,但很容易过滤掉