将Java 8中的List<V>转换为Map<K, V>

1047

我想使用Java 8的流和lambda将对象列表转换为Map。

这是我在Java 7及以下版本中的写法。

private Map<String, Choice> nameMap(List<Choice> choices) {
        final Map<String, Choice> hashMap = new HashMap<>();
        for (final Choice choice : choices) {
            hashMap.put(choice.getName(), choice);
        }
        return hashMap;
}

我可以使用Java 8和Guava轻松实现这一点,但我想知道如何在不使用Guava的情况下完成。

在Guava中:

private Map<String, Choice> nameMap(List<Choice> choices) {
    return Maps.uniqueIndex(choices, new Function<Choice, String>() {

        @Override
        public String apply(final Choice input) {
            return input.getName();
        }
    });
}

还有Java8 lambda的番石榴。

private Map<String, Choice> nameMap(List<Choice> choices) {
    return Maps.uniqueIndex(choices, Choice::getName);
}
23个回答

11

我试图做到这一点,并发现在使用上面的答案时,当将Functions.identity()用作Map的键时,使用像this::localMethodName这样的本地方法实际上无法工作,因为存在类型问题。

Functions.identity()实际上在这种情况下对类型进行了某些更改,因此该方法只能通过返回Object并接受Object参数来工作。

为了解决这个问题,我最终放弃了Functions.identity(),改用s->s

因此,我的代码,在我的情况下列出目录中的所有目录,并为每个目录使用目录名称作为键来调用一个方法,并返回一组项目,看起来像:

Map<String, Collection<ItemType>> items = Arrays.stream(itemFilesDir.listFiles(File::isDirectory))
.map(File::getName)
.collect(Collectors.toMap(s->s, this::retrieveBrandItems));

8
我使用这个语法。
Map<Integer, List<Choice>> choiceMap = 
choices.stream().collect(Collectors.groupingBy(choice -> choice.getName()));

11
groupingBy创建的是一个Map<K,List<V>>,而不是一个Map<K,V> - Christoffer Hammarström
4
复制于ulises的回答。还有,String getName();(不是Integer)。 - Barett

8

还有一个目前只存在于评论中的可能性:

Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(c -> c.getName(), c -> c)));

如果你想使用子对象的参数作为键,这将非常有用:

Map<String, Choice> result =
choices.stream().collect(Collectors.toMap(c -> c.getUser().getName(), c -> c)));

7

可以使用流来实现此操作。为了消除显式使用Collectors的需要,可以静态导入toMap(如Effective Java第三版所建议)。

import static java.util.stream.Collectors.toMap;

private static Map<String, Choice> nameMap(List<Choice> choices) {
    return choices.stream().collect(toMap(Choice::getName, it -> it));
}

5

这可以通过两种方式完成。让 person 成为我们要用来演示的类。

public class Person {

    private String name;
    private int age;

    public String getAge() {
        return age;
    }
}

persons成为要转换为映射的人员列表

1.在列表上使用简单的foreach和Lambda表达式

Map<Integer,List<Person>> mapPersons = new HashMap<>();
persons.forEach(p->mapPersons.put(p.getAge(),p));

2. 在给定的列表上使用Collectors流操作。

 Map<Integer,List<Person>> mapPersons = 
           persons.stream().collect(Collectors.groupingBy(Person::getAge));

5
Map<String, Set<String>> collect = Arrays.asList(Locale.getAvailableLocales()).stream().collect(Collectors
                .toMap(l -> l.getDisplayCountry(), l -> Collections.singleton(l.getDisplayLanguage())));

3
Map<String,Choice> map=list.stream().collect(Collectors.toMap(Choice::getName, s->s));

即使对我而言,这也能达到目的。

Map<String,Choice> map=  list1.stream().collect(()-> new HashMap<String,Choice>(), 
            (r,s) -> r.put(s.getString(),s),(r,s) -> r.putAll(s));

3
这里提供了使用StreamEx的解决方案。
StreamEx.of(choices).toMap(Choice::getName, c -> c);

3

如果需要覆盖相同键名称的每个新值:

public Map < String, Choice > convertListToMap(List < Choice > choices) {
    return choices.stream()
        .collect(Collectors.toMap(Choice::getName,
            Function.identity(),
            (oldValue, newValue) - > newValue));
}

如果所有选项都需要按名称分组列在列表中:
public Map < String, Choice > convertListToMap(List < Choice > choices) {
    return choices.stream().collect(Collectors.groupingBy(Choice::getName));
}

1
List<V> choices; // your list
Map<K,V> result = choices.stream().collect(Collectors.toMap(choice::getKey(),choice));
//assuming class "V" has a method to get the key, this method must handle case of duplicates too and provide a unique key.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接