关于lambda:Java 8 List into Map

Java 8 List<V> into Map<K, V>

我想用Java 8的流和LAMBDAS将对象列表翻译成一个映射。

这就是我在Java 7和下面写的方法。

1
2
3
4
5
6
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和番石榴来完成这件事,但我想知道如何在没有番石榴的情况下做到这一点。

番石榴:

1
2
3
4
5
6
7
8
9
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();
        }
    });
}

和番石榴与爪哇8 lambdas。

1
2
3
private Map<String, Choice> nameMap(List<Choice> choices) {
    return Maps.uniqueIndex(choices, Choice::getName);
}


基于Collectors文档,它简单如下:

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


如果您的密钥不能保证对列表中的所有元素都是唯一的,则应将其转换为Map>,而不是Map

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


使用getname()作为键,选择本身作为映射的值:

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


这是另外一个,以防您不想使用Collectors.tomap()。

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


列出的大多数答案,如果列表中有重复项,则会错过一个案例。在这种情况下,答案将抛出IllegalStateException。请参阅以下代码以处理列表重复项:

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

One more option in simple way

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


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

实例对象:

1
2
3
4
5
6
7
8
9
10
11
class Item{
        private String code;
        private String name;

        public Item(String code, String name) {
            this.code = code;
            this.name = name;
        }

        //getters and setters
    }

操作将列表转换为映射:

1
2
3
4
5
6
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));

如果您不介意使用第三方库,AOL的cyclops react lib(公开我是一个贡献者)对所有JDK集合类型(包括list和map)都有扩展。

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

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

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

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

因此,在我的例子中,我的代码列出了一个目录中的所有目录,对于每个目录,使用目录的名称作为映射的键,然后使用目录名称调用一个方法并返回一组项,如下所示:

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

可以使用intstream创建索引流,然后将其转换为映射:

1
2
3
4
Map<Integer,Item> map =
IntStream.range(0,items.size())
         .boxed()
         .collect(Collectors.toMap (i -> i, i -> items.get(i)));


我用这个语法

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


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

也许我们有整数列表或者对象列表。所以问题是:地图的关键应该是什么?

创建接口

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

现在使用控制反转:

1
2
3
  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));
    }

例如,如果我们有book对象,这个类将选择映射的键

1
2
3
4
5
6
public class BookKeyFinder implements KeyFinder<Long, Book> {
    @Override
    public Long getKey(Book e) {
        return e.getPrice()
    }
}

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

可以使用流来执行此操作。为了省去明确使用EDCOX1(0)的可能,可以静态地导入EDCOX1 OR 11(如有效Java推荐的第三版)。

1
2
3
4
5
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));
}

这里是streamex的解决方案

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

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

甚至为我服务,

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


这可以通过两种方式实现。让人成为我们将用来演示的课堂。

1
2
3
4
5
6
7
8
9
public class Person {

    private String name;
    private int age;

    public String getAge() {
        return age;
    }
}

让人成为要转换为地图的人的列表

1.使用简单的foreach和列表中的lambda表达式

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
If every new value for the same key name has to be overidden
then below will be the code :

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

If all choices have to be grouped in a list for a name then
below will be the code:

      public Map<String, Choice>
       convertListToMap(List<Choice> choices) {
       return choices.stream().collect(Collectors.groupingBy(Choice::getName));
  }

1
2
3
4
5
6
7
8
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);

双重密钥AA12=asdfasdf,7=eedddad,4=cccc,3=bbb,2=aa_