Java8 List<V>转换成Map<K, V>

我想使用Java8的流和lambdas将对象列表转换为地图。

这就是我在7Java及以下的写作方式。

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;}

我可以使用Java8和番石榴轻松完成此操作,但我想知道如何在没有番石榴的情况下做到这一点。

在番石榴:

private Map<String, Choice> nameMap(List<Choice> choices) {return Maps.uniqueIndex(choices, new Function<Choice, String>() {
@Overridepublic String apply(final Choice input) {return input.getName();}});}

番石榴和Java8 lambdas。

private Map<String, Choice> nameMap(List<Choice> choices) {return Maps.uniqueIndex(choices, Choice::getName);}
721344 次浏览

基于#0留档,它很简单:

Map<String, Choice> result =choices.stream().collect(Collectors.toMap(Choice::getName,Function.identity()));

如果键不是保证对列表中的所有元素都是唯一的,则应将其转换为Map<String, List<Choice>>而不是Map<String, Choice>

Map<String, List<Choice>> result =choices.stream().collect(Collectors.groupingBy(Choice::getName));

使用getName()作为键,Choice本身作为map的值:

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

我使用这种语法

Map<Integer, List<Choice>> choiceMap =choices.stream().collect(Collectors.groupingBy(choice -> choice.getName()));

我试图这样做,发现,使用上面的答案,当使用Functions.identity()作为Map的键时,由于键入问题,我在使用像this::localMethodName这样的本地方法实际工作时遇到了问题。

在这种情况下,Functions.identity()实际上对键入做了一些事情,因此该方法只能通过返回Object并接受Object的参数来工作

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

所以我的代码,在我的例子中,列出目录中的所有目录,对于每个目录,使用目录的名称作为map的键,然后使用目录名称调用方法并返回项目集合,看起来像:

Map<String, Collection<ItemType>> items = Arrays.stream(itemFilesDir.listFiles(File::isDirectory)).map(File::getName).collect(Collectors.toMap(s->s, this::retrieveBrandItems));
Map<String, Set<String>> collect = Arrays.asList(Locale.getAvailableLocales()).stream().collect(Collectors.toMap(l -> l.getDisplayCountry(), l -> Collections.singleton(l.getDisplayLanguage())));

如果您不介意使用第三方库,AOL的独眼巨人反应 lib(披露我是贡献者)对所有JDK集合类型都有扩展,包括列表地图

ListX<Choices> choices;Map<String, Choice> map = choices.toMap(c-> c.getName(),c->c);

这是另一个,以防你不想使用Collectors.to地图()

Map<String, Choice> result =choices.stream().collect(HashMap<String, Choice>::new,(m, c) -> m.put(c.getName(), c),(m, u) -> {});

还有一个简单的选择

Map<String,Choice> map = new HashMap<>();choices.forEach(e->map.put(e.getName(),e));

这里是解决方案StreamEx

StreamEx.of(choices).toMap(Choice::getName, c -> c);

您可以使用IntStream创建索引流,然后将它们转换为Map:

Map<Integer,Item> map =IntStream.range(0,items.size()).boxed().collect(Collectors.toMap (i -> i, i -> items.get(i)));
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));

例如,如果要将对象字段转换为map:

示例对象:

class Item{private String code;private String name;
public Item(String code, String name) {this.code = code;this.name = name;}
//getters and setters}

和操作转换列表到映射:

List<Item> list = new ArrayList<>();list.add(new Item("code1", "name1"));list.add(new Item("code2", "name2"));
Map<String,String> map = list.stream().collect(Collectors.toMap(Item::getCode, Item::getName));

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

public class Person {
private String name;private int age;
public String getAge() {return age;}}

为要转换为地图的人员列表

1.在列表中使用简单Foreach和Lambda表达式

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

2.使用给定列表上定义的Stream上的收集器。

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

可以使用流来执行此操作。为了消除显式使用Collectors的需要,可以静态导入toMap(根据有效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));}

我将写如何使用泛型控制反转将列表转换为映射。只是通用方法!

也许吧我们有整数列表物体。的列表,所以问题如下:应该是什么地图的钥匙?

创建接口

public interface KeyFinder<K, E> {K getKey(E e);}

现在使用控制反转:

  static <K, E> Map<K, E> listToMap(List<E> list, KeyFinder<K, E> finder) {return  list.stream().collect(Collectors.toMap(e -> finder.getKey(e) , e -> e));}

例如,如果我们有书的对象,这个类是为地图选择键

public class BookKeyFinder implements KeyFinder<Long, Book> {@Overridepublic Long getKey(Book e) {return e.getPrice()}}

列出的大多数答案,当列表有重复项时错过一个案例。在这种情况下,答案将抛出IllegalStateException。也参考下面的代码处理列表重复

public Map<String, Choice> convertListToMap(List<Choice> choices) {return choices.stream().collect(Collectors.toMap(Choice::getName, choice -> choice,(oldValue, newValue) -> newValue));}
List<Integer> listA = new ArrayList<>();listA.add(1);listA.add(5);listA.add(3);listA.add(4);

System.out.println(listA.stream().collect(Collectors.toMap(x ->x, x->x)));

如果必须覆盖相同键名的每个新值:

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));}
String array[] = {"ASDFASDFASDF","AA", "BBB", "CCCC", "DD", "EEDDDAD"};List<String> list = Arrays.asList(array);Map<Integer, String> map = list.stream().collect(Collectors.toMap(s -> s.length(), s -> s, (x, y) -> {System.out.println("Dublicate key" + x);return x;},()-> new TreeMap<>((s1,s2)->s2.compareTo(s1))));System.out.println(map);

重复密钥AA

{12=ASDFASDFASDF, 7=EEDDDAD, 4=CCCC, 3=BBB, 2=AA}
List<V> choices; // your listMap<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.

作为guava的替代品,可以使用kotlin-stdlib

private Map<String, Choice> nameMap(List<Choice> choices) {return CollectionsKt.associateBy(choices, Choice::getName);}

另一种可能性只出现在评论中:

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

如果您想将子对象的参数用作Key,则很有用:

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