преобразовать список в hashmap в java, используя stream api [duplicate]

Встроенный div является уродцем сети и amp; должен быть избит до тех пор, пока он не станет промежутком (по крайней мере 9 раз из 10) ...

<span>foo</span>
<span>bar</span>
<span>baz</span>

... отвечает на исходный вопрос ...

727
задан Vitruvius 30 May 2018 в 22:10
поделиться

18 ответов

На основе Collectors документации это так же просто, как:

Map<String, Choice> result =
    choices.stream().collect(Collectors.toMap(Choice::getName,
                                              Function.identity()));
1050
ответ дан Alexis C. 17 August 2018 в 10:04
поделиться
  • 1
    В качестве примечания, даже после Java 8, JDK по-прежнему не может участвовать в конкурсе на краткость. Альтернатива Guava выглядит настолько читаемой: Maps.uniqueIndex(choices, Choice::getName). – Bogdan Calmac 3 March 2015 в 18:59
  • 2
    @BogdanCalmac Это довольно тривиально написать такой метод uniqueIndex() самостоятельно в Java 8. – herman 28 August 2016 в 21:37
  • 3
    Есть ли преимущества использования функции. Я имею в виду, это - & gt; он короче – shabunc 30 May 2017 в 12:49
  • 4
    @shabunc Я не знаю никакой пользы и фактически использую it -> it сам. Function.identity() используется здесь главным образом потому, что он используется в ссылочной документации, и это все, что я знал о лямбдах во время написания – zapl 30 May 2017 в 12:57
  • 5
    @zapl, о, на самом деле выясняется, что есть причины этого - stackoverflow.com/questions/28032827/… – shabunc 30 May 2017 в 13:39

Используйте getName () как ключ и сам выбор как значение карты:

Map<String, Choice> result =
    choices.stream().collect(Collectors.toMap(Choice::getName, c -> c));
109
ответ дан Chei 17 August 2018 в 10:04
поделиться
  • 1
    Пожалуйста, напишите некоторое описание, чтобы пользователь мог понять. – Mayank Jain 28 February 2015 в 08:38
  • 2
    Это очень плохо, здесь нет более подробных сведений, потому что мне нравится этот ответ лучше всего. – MadConan 24 November 2015 в 14:50
  • 3
    Он равен choices.stream().collect(Collectors.toMap(choice -> choice.getName(),choice -> choice)); Первая функция для ключа, вторая функция для значения – waterscar 6 January 2016 в 08:29
  • 4
    Я знаю, как легко видеть и понимать c -> c, но Function.identity() несет большую семантическую информацию. Обычно я использую статический импорт, так что я могу просто использовать identity() – Hank D 9 April 2016 в 21:06
  • 5
    Читайте здесь @HankD stackoverflow.com/a/28041480/3488928 – Ashish Lohia 12 July 2017 в 05:45

Вот еще один случай, если вы не хотите использовать Collectors.toMap ()

Map<String, Choice> result =
   choices.stream().collect(HashMap<String, Choice>::new, 
                           (m, c) -> m.put(c.getName(), c),
                           (m, u) -> {});
11
ответ дан Emre Colak 17 August 2018 в 10:04
поделиться
  • 1
    Что лучше использовать тогда Collectors.toMap() или наш собственный HashMap, как вы показали в приведенном выше примере? – Swapnil Gangrade 18 July 2016 в 14:22
  • 2
    В этом примере приведен пример того, как разместить на карте что-то еще. Я хотел, чтобы значение не предоставлялось вызовом метода. Благодаря! – th3morg 21 April 2017 в 01:51
  • 3
    Третья функция аргумента неверна. Там вы должны предоставить некоторую функцию для объединения двух Hashmaps, что-то вроде Hashmap :: putAll – jesantana 21 July 2017 в 08:34

Я напишу, как преобразовать список в карту с помощью дженериков и инверсии элемента управления. Просто универсальный метод!

Возможно, у нас есть список целых чисел или список объектов. Итак, вопрос заключается в следующем: что должно быть ключом к карте?

создать интерфейс

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> {
    @Override
    public Long getKey(Book e) {
        return e.getPrice()
    }
}
1
ответ дан grep 17 August 2018 в 10:04
поделиться

Если вы не против использовать сторонний lib ( Vavr (ранее известный как Javaslang) ), вы можете использовать мощные новые неизменные коллекции:

// import javaslang.collection.*;
Map<String, Choice> map = list.toMap(choice -> Tuple.of(choice.getName(), choice));

Там также много методов для преобразования Java-коллекций вперед и назад.

Пожалуйста, прочитайте подробнее о новых коллекциях здесь.

Отказ от ответственности: я являюсь создателем Vavr.

10
ответ дан Grzegorz Piwowarek 17 August 2018 в 10:04
поделиться

Я пытался это сделать и обнаружил, что, используя ответы выше, при использовании Functions.identity() для ключа к карте, у меня возникли проблемы с использованием локального метода, такого как 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));
7
ответ дан iZian 17 August 2018 в 10:04
поделиться

Если вы не возражаете против использования сторонних библиотек, AOL cyclops-react lib (раскрытие я являюсь вкладчиком) имеет расширения для всех типов JDK Collection , включая Список и Карта .

ListX<Choices> choices;
Map<String, Choice> map = choices.toMap(c-> c.getName(),c->c);
9
ответ дан John McClean 17 August 2018 в 10:04
поделиться

Для этого можно использовать потоки. Чтобы удалить необходимость явно использовать 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));
}
0
ответ дан Konrad Borowski 17 August 2018 в 10:04
поделиться

Например, если вы хотите преобразовать объектные поля в карту:

Пример объекта:

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()));
6
ответ дан Piotr Rogowski 17 August 2018 в 10:04
поделиться

Это можно сделать двумя способами. Пусть человек будет классом, который мы собираемся использовать для его демонстрации.

public class Person {

    private String name;
    private int age;

    public String getAge() {
        return age;
    }
}

Пусть люди являются списком лиц, которые будут преобразованы в карту

1.Использование Простой foreach и лямбда-выражение в списке

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

2. Использование коллекторов в потоке, определенных в данном списке.

 Map<Integer,List<Person>> mapPersons = 
           persons.stream().collect(Collectors.groupingBy(Person::getAge));
0
ответ дан raja emani 17 August 2018 в 10:04
поделиться
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));
0
ответ дан Rajeev Akotkar 17 August 2018 в 10:04
поделиться

Еще один вариант простым способом

Map<String,Choice> map = new HashMap<>();
choices.forEach(e->map.put(e.getName(),e));
10
ответ дан Renukeswar 17 August 2018 в 10:04
поделиться
  • 1
    Нет никакой реальной разницы в использовании этого или java 7-го типа. – Ashish Lohia 12 July 2017 в 05:39
  • 2
    Мне было легче читать и понимать, что происходит, чем другие механизмы – Freiheit 11 January 2018 в 19:47
  • 3
    SO спросил с Java 8 Streams. – Mehraj Malik 30 March 2018 в 11:09

В большинстве приведенных ответов пропустите случай, когда список имеет повторяющиеся элементы. В этом случае ответ будет кидать IllegalStateException. См. Приведенный ниже код для обработки дубликатов списков:

public Map<String, Choice> convertListToMap(List<Choice> choices) {
    return choices.stream()
        .collect(Collectors.toMap(Choice::getName, choice -> choice,
            (oldValue, newValue) -> newValue));
  }
0
ответ дан Sahil Chhabra 17 August 2018 в 10:04
поделиться

Если ваш ключ НЕ гарантированно уникален для всех элементов в списке, вы должны преобразовать его в Map<String, List<Choice>> вместо Map<String, Choice>

Map<String, List<Choice>> result =
 choices.stream().collect(Collectors.groupingBy(Choice::getName));
207
ответ дан stkent 17 August 2018 в 10:04
поделиться
  • 1
    Это фактически дает вам Map & lt; String, List & lt; Choice & gt; & gt; & gt; который имеет дело с возможностью не-уникальных ключей, но это не то, что запросил ОП. В Guava Multimaps.index (выбор, Choice :: getName), вероятно, является лучшим вариантом, если это так, как вы хотите. – Richard Nichols 29 October 2014 в 05:41
  • 2
    хороший ответ. благодаря... – Braj 22 February 2018 в 07:26
  • 3
    или, скорее, использовать Multimap Guava & lt; String, Choice & gt; что весьма удобно в сценариях, где одни и те же ключевые карты сопоставляются с несколькими значениями. В Гуаве доступны различные методы утилиты для использования таких структур данных, а не для создания карты & lt; String, List & lt; Choice & gt; & gt; & gt; – Neeraj B. 6 July 2018 в 14:03
Map<String, Set<String>> collect = Arrays.asList(Locale.getAvailableLocales()).stream().collect(Collectors
                .toMap(l -> l.getDisplayCountry(), l -> Collections.singleton(l.getDisplayLanguage())));
3
ответ дан Tunaki 17 August 2018 в 10:04
поделиться

Я использую этот синтаксис

Map<Integer, List<Choice>> choiceMap = 
choices.stream().collect(Collectors.groupingBy(choice -> choice.getName()));
4
ответ дан user2069723 17 August 2018 в 10:04
поделиться
  • 1
    groupingBy создает Map<K,List<V>>, а не Map<K,V>. – Christoffer Hammarström 4 June 2015 в 15:42
  • 2
    Дуп из улизов отвечает. И String getName(); (не целое) – Barett 2 December 2015 в 19:53

Вот решение StreamEx

StreamEx.of(choices).toMap(Choice::getName, c -> c);
1
ответ дан user_3380739 17 August 2018 в 10:04
поделиться

Вы можете создать поток индексов с помощью IntStream, а затем преобразовать их в Map:

Map<Integer,Item> map = 
IntStream.range(0,items.size())
         .boxed()
         .collect(Collectors.toMap (i -> i, i -> items.get(i)));
4
ответ дан Vikas Suryawanshi 17 August 2018 в 10:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: