Самый простой способ объединить два списка в карту (Java)? - PullRequest
52 голосов
/ 03 декабря 2009

Было бы неплохо использовать for (String item: list), но он будет перебирать только один список, и вам понадобится явный итератор для другого списка. Или вы можете использовать явный итератор для обоих.

Вот пример проблемы и решение, использующее вместо этого индексированный цикл for:

import java.util.*;
public class ListsToMap {
  static public void main(String[] args) {
    List<String> names = Arrays.asList("apple,orange,pear".split(","));
    List<String> things = Arrays.asList("123,456,789".split(","));
    Map<String,String> map = new LinkedHashMap<String,String>();  // ordered

    for (int i=0; i<names.size(); i++) {
      map.put(names.get(i), things.get(i));    // is there a clearer way?
    }

    System.out.println(map);
  }
}

Выход:

{apple=123, orange=456, pear=789}

Есть ли более ясный способ? Может быть, в коллекции API где-нибудь?

Ответы [ 15 ]

1 голос
/ 27 июня 2018

Другое решение Java 8:

Если у вас есть доступ к библиотеке Guava (самая ранняя поддержка потоков в версии 21 [1] ), вы можете сделать:

Streams.zip(keyList.stream(), valueList.stream(), Maps::immutableEntry)
       .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

Для меня преимущество этого метода просто заключается в том, что он является однострочным, и я нашел это полезным для моего варианта использования.

1 голос
/ 27 января 2018

Это работает с использованием Eclipse Collections .

Map<String, String> map =
        Maps.adapt(new LinkedHashMap<String, String>())
                .withAllKeyValues(
                        Lists.mutable.of("apple,orange,pear".split(","))
                                .zip(Lists.mutable.of("123,456,789".split(","))));

System.out.println(map);

Примечание: я являюсь коммиттером для Eclipse Collections.

1 голос
/ 03 декабря 2009

Используйте Clojure. одна строка - все, что нужно;)

 (zipmap list1 list2)
0 голосов
/ 14 февраля 2018

В Java 8 я просто перебрал бы и то и другое по одному и заполнил карту:

public <K, V> Map<K, V> combineListsIntoOrderedMap (Iterable<K> keys, Iterable<V> values) {

    Map<K, V> map = new LinkedHashMap<>();

    Iterator<V> vit = values.iterator();
    for (K k: keys) {
        if (!vit.hasNext())
            throw new IllegalArgumentException ("Less values than keys.");

        map.put(k, vit.next());
    }

    return map;
}

Или вы можете пойти еще дальше с функциональным стилем и сделать:

/**
 * Usage:
 *
 *     Map<K, V> map2 = new LinkedHashMap<>();
 *     combineListsIntoOrderedMap(keys, values, map2::put);
 */
public <K, V> void combineListsIntoOrderedMap (Iterable<K> keys, Iterable<V> values, BiConsumer<K, V> onItem) {
    Iterator<V> vit = values.iterator();
    for (K k: keys) {
        if (!vit.hasNext())
            throw new IllegalArgumentException ("Less values than keys.");
        onItem.accept(k, vit.next());
    }
}
0 голосов
/ 10 мая 2016

Другая перспектива - скрыть реализацию. Хотели бы вы, чтобы вызывающая сторона этой функции наслаждалась внешним видом расширенного цикла for Java ?

public static void main(String[] args) {
    List<String> names = Arrays.asList("apple,orange,pear".split(","));
    List<String> things = Arrays.asList("123,456,789".split(","));
    Map<String, String> map = new HashMap<>(4);
    for (Map.Entry<String, String> e : new DualIterator<>(names, things)) {
        map.put(e.getKey(), e.getValue());
    }
    System.out.println(map);
}

Если да (Map.Entry выбрано для удобства), то вот полный пример (примечание: поток небезопасен ):

import java.util.*;
/** <p>
    A thread unsafe iterator over two lists to convert them 
    into a map such that keys in first list at a certain
    index map onto values in the second list <b> at the same index</b>.
    </p>
    Created by kmhaswade on 5/10/16.
 */
public class DualIterator<K, V> implements Iterable<Map.Entry<K, V>> {
    private final List<K> keys;
    private final List<V> values;
    private int anchor = 0;

    public DualIterator(List<K> keys, List<V> values) {
        // do all the validations here
        this.keys = keys;
        this.values = values;
    }
    @Override
    public Iterator<Map.Entry<K, V>> iterator() {
        return new Iterator<Map.Entry<K, V>>() {
            @Override
            public boolean hasNext() {
                return keys.size() > anchor;
            }

            @Override
            public Map.Entry<K, V> next() {
                Map.Entry<K, V> e = new AbstractMap.SimpleEntry<>(keys.get(anchor), values.get(anchor));
                anchor += 1;
                return e;
            }
        };
    }

    public static void main(String[] args) {
        List<String> names = Arrays.asList("apple,orange,pear".split(","));
        List<String> things = Arrays.asList("123,456,789".split(","));
        Map<String, String> map = new LinkedHashMap<>(4);
        for (Map.Entry<String, String> e : new DualIterator<>(names, things)) {
            map.put(e.getKey(), e.getValue());
        }
        System.out.println(map);
    }
}

Он печатает (по требованию):

{apple=123, orange=456, pear=789}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...