Frage

Vor kurzem habe ich Gespräch mit einem Kollegen über das, was der optimalen Weg in Java und wenn es spezifische Vorteile, dies zu tun.

zu konvertieren List zu Map wäre

Ich möchte eine optimale Umwandlung Ansatz wissen und würde wirklich schätzen, wenn jemand mich leiten kann.

Ist der gute Ansatz:

List<Object[]> results;
Map<Integer, String> resultsMap = new HashMap<Integer, String>();
for (Object[] o : results) {
    resultsMap.put((Integer) o[0], (String) o[1]);
}
War es hilfreich?

Lösung

List<Item> list;
Map<Key,Item> map = new HashMap<Key,Item>();
for (Item i : list) map.put(i.getKey(),i);

natürlich Unter der Annahme, dass jedes Element hat eine getKey() Methode, dass die Rendite einen Schlüssel vom richtigen Typ.

Andere Tipps

Mit , können Sie diese mit in einer Zeile tun und Collectors Klasse.

Map<String, Item> map = 
    list.stream().collect(Collectors.toMap(Item::getKey, item -> item));

Kurze Demo:

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Test{
    public static void main (String [] args){
        List<Item> list = IntStream.rangeClosed(1, 4)
                                   .mapToObj(Item::new)
                                   .collect(Collectors.toList()); //[Item [i=1], Item [i=2], Item [i=3], Item [i=4]]

        Map<String, Item> map = 
            list.stream().collect(Collectors.toMap(Item::getKey, item -> item));

        map.forEach((k, v) -> System.out.println(k + " => " + v));
    }
}
class Item {

    private final int i;

    public Item(int i){
        this.i = i;
    }

    public String getKey(){
        return "Key-"+i;
    }

    @Override
    public String toString() {
        return "Item [i=" + i + "]";
    }
}

Ausgabe:

Key-1 => Item [i=1]
Key-2 => Item [i=2]
Key-3 => Item [i=3]
Key-4 => Item [i=4]

Wie bereits erwähnt in den Kommentaren, können Sie Function.identity() statt item -> item verwenden, obwohl ich i -> i eher explizit finden.

Und vollständige Kenntnis, dass Sie einen binären Operator verwenden können, wenn Ihre Funktion nicht bijektiv ist. Zum Beispiel lassen betrachten die diese List und die Mapping-Funktion, die für einen int-Wert, um das Ergebnis berechnen davon 3 Modulo:

List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5, 6);
Map<String, Integer> map = 
    intList.stream().collect(toMap(i -> String.valueOf(i % 3), i -> i));

Wenn Sie diesen Code ausführen, erhalten Sie eine Fehlermeldung, dass java.lang.IllegalStateException: Duplicate key 1 bekommen. Dies liegt daran, dass 1% 3 ist die gleiche wie 4% 3 und damit den gleichen Schlüsselwert der Schlüssel-Mapping-Funktion gegeben haben. In diesem Fall können Sie einen Merge-Operator zur Verfügung stellen.

Hier ist eine, die Summe der Werte; (i1, i2) -> i1 + i2;, die mit dem Verfahren Referenz Integer::sum ersetzt werden können.

Map<String, Integer> map = 
    intList.stream().collect(toMap(i -> String.valueOf(i % 3), 
                                   i -> i, 
                                   Integer::sum));

, die jetzt gibt:

0 => 9 (i.e 3 + 6)
1 => 5 (i.e 1 + 4)
2 => 7 (i.e 2 + 5)

Hope, es hilft! :)

Für den Fall, diese Frage nicht als Duplikat geschlossen, ist Google Sammlungen zu verwenden:

Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, new Function<Role,String>() {
  public String apply(Role from) {
    return from.getName(); // or something else
  }});

Da Java 8, die Antwort von @ZouZou der Collectors.toMap Kollektor ist sicherlich der idiomatische Weg, um dieses Problem zu lösen.

Und das ist so eine gemeinsame Aufgabe, können wir es in einen statischen Nutzen machen.

Auf diese Weise die Lösung wirklich zu einem Einzeiler.

/**
 * Returns a map where each entry is an item of {@code list} mapped by the
 * key produced by applying {@code mapper} to the item.
 *
 * @param list the list to map
 * @param mapper the function to produce the key from a list item
 * @return the resulting map
 * @throws IllegalStateException on duplicate key
 */
public static <K, T> Map<K, T> toMapBy(List<T> list,
        Function<? super T, ? extends K> mapper) {
    return list.stream().collect(Collectors.toMap(mapper, Function.identity()));
}

Und hier ist, wie Sie es auf einem List<Student> verwenden würden:

Map<Long, Student> studentsById = toMapBy(students, Student::getId);

Mit Java 8 können Sie wie folgt vorgehen:

Map<Key, Value> result= results
                       .stream()
                       .collect(Collectors.toMap(Value::getName,Function.identity()));

Value kann jedes Objekt, das Sie verwenden.

Ein List und Map sind vom Konzept her unterschiedlich. Ein List ist eine geordnete Sammlung von Gegenständen. Die Elemente können Duplikate enthalten, und ein Element eventuell gar kein Konzept einer eindeutigen Kennung (key). Ein Map hat Werte Tasten zugeordnet. Jeder Schlüssel kann nur auf einen Wert zeigen.

Daher je nach List Artikeln, kann es oder auch nicht möglich sein, es zu einem Map zu konvertieren. Hat Items List die keine Duplikate haben? Hat jedes Element einen eindeutigen Schlüssel haben? Wenn ja, dann ist es möglich, sie in einem Map zu setzen.

Es gibt auch eine einfache Möglichkeit, dies zu tun, mit Maps.uniqueIndex (...) von Google Bibliotheken

Alexis hat geschrieben bereits eine Antwort in Java 8 mit der Methode toMap(keyMapper, valueMapper). Per doc für diese Methode Implementierung:

  

Es gibt keine Garantien über die Art, Wandelbarkeit, Serialisierung, oder   Thread-Sicherheit der Karte zurückgegeben.

So im Fall sind wir in einer spezifischen Implementierung Map Schnittstelle zum Beispiel interessieren HashMap dann können wir die überladene Form wie verwenden:

Map<String, Item> map2 =
                itemList.stream().collect(Collectors.toMap(Item::getKey, //key for map
                        Function.identity(),    // value for map
                        (o,n) -> o,             // merge function in case of conflict with keys
                        HashMap::new));         // map factory - we want HashMap and not any Map implementation

Obwohl entweder Function.identity() oder i->i verwendet, ist in Ordnung, aber es scheint Function.identity() statt i -> i könnte etwas Speicher gemäß diesem Stand der Antwort speichern .

Universal-Methode

public static <K, V> Map<K, V> listAsMap(Collection<V> sourceList, ListToMapConverter<K, V> converter) {
    Map<K, V> newMap = new HashMap<K, V>();
    for (V item : sourceList) {
        newMap.put( converter.getKey(item), item );
    }
    return newMap;
}

public static interface ListToMapConverter<K, V> {
    public K getKey(V item);
}

Ohne Java-8, können Sie diese Commons Sammlungen in einer Zeile zu tun, und die Schließung Klasse

List<Item> list;
@SuppressWarnings("unchecked")
Map<Key, Item> map  = new HashMap<Key, Item>>(){{
    CollectionUtils.forAllDo(list, new Closure() {
        @Override
        public void execute(Object input) {
            Item item = (Item) input;
            put(i.getKey(), item);
        }
    });
}};

Viele Lösungen in den Sinn kommen, je nachdem, was Sie wollen achive:

Jeder Listenpunkt ist der Schlüssel und Wert

for( Object o : list ) {
    map.put(o,o);
}

Listenelemente haben etwas, sie zu sehen, vielleicht einen Namen:

for( MyObject o : list ) {
    map.put(o.name,o);
}

Listenelemente haben etwas, sie zu sehen, und es gibt keine Garantie, dass sie einzigartig sind: Verwenden Sie Googles MultiMaps

for( MyObject o : list ) {
    multimap.put(o.name,o);
}

Geben alle Elemente, die Position als Schlüssel:

for( int i=0; i<list.size; i++ ) {
    map.put(i,list.get(i));
}

...

Es hängt wirklich davon ab, was Sie achive wollen.

Wie Sie aus den Beispielen sehen können, ist eine Karte eine Abbildung von einem Schlüssel auf einen Wert, während eine Liste nur eine Reihe von Elementen ist jeweils eine Position. So sind sie einfach nicht automatisch konvertierbar.

Hier ist eine kleine Methode, die ich für genau diesen Zweck geschrieben. Es verwendet Validate von Apache Commons.

Fühlen Sie sich frei, es zu benutzen.

/**
 * Converts a <code>List</code> to a map. One of the methods of the list is called to retrive
 * the value of the key to be used and the object itself from the list entry is used as the
 * objct. An empty <code>Map</code> is returned upon null input.
 * Reflection is used to retrieve the key from the object instance and method name passed in.
 *
 * @param <K> The type of the key to be used in the map
 * @param <V> The type of value to be used in the map and the type of the elements in the
 *            collection
 * @param coll The collection to be converted.
 * @param keyType The class of key
 * @param valueType The class of the value
 * @param keyMethodName The method name to call on each instance in the collection to retrieve
 *            the key
 * @return A map of key to value instances
 * @throws IllegalArgumentException if any of the other paremeters are invalid.
 */
public static <K, V> Map<K, V> asMap(final java.util.Collection<V> coll,
        final Class<K> keyType,
        final Class<V> valueType,
        final String keyMethodName) {

    final HashMap<K, V> map = new HashMap<K, V>();
    Method method = null;

    if (isEmpty(coll)) return map;
    notNull(keyType, Messages.getString(KEY_TYPE_NOT_NULL));
    notNull(valueType, Messages.getString(VALUE_TYPE_NOT_NULL));
    notEmpty(keyMethodName, Messages.getString(KEY_METHOD_NAME_NOT_NULL));

    try {
        // return the Method to invoke to get the key for the map
        method = valueType.getMethod(keyMethodName);
    }
    catch (final NoSuchMethodException e) {
        final String message =
            String.format(
                    Messages.getString(METHOD_NOT_FOUND),
                    keyMethodName,
                    valueType);
        e.fillInStackTrace();
        logger.error(message, e);
        throw new IllegalArgumentException(message, e);
    }
    try {
        for (final V value : coll) {

            Object object;
            object = method.invoke(value);
            @SuppressWarnings("unchecked")
            final K key = (K) object;
            map.put(key, value);
        }
    }
    catch (final Exception e) {
        final String message =
            String.format(
                    Messages.getString(METHOD_CALL_FAILED),
                    method,
                    valueType);
        e.fillInStackTrace();
        logger.error(message, e);
        throw new IllegalArgumentException(message, e);
    }
    return map;
}

Sie können nutzen die Streams API von Java 8.

public class ListToMap {

  public static void main(String[] args) {
    List<User> items = Arrays.asList(new User("One"), new User("Two"), new User("Three"));

    Map<String, User> map = createHashMap(items);
    for(String key : map.keySet()) {
      System.out.println(key +" : "+map.get(key));
    }
  }

  public static Map<String, User> createHashMap(List<User> items) {
    Map<String, User> map = items.stream().collect(Collectors.toMap(User::getId, Function.identity()));
    return map;
  }
}

Weitere Informationen finden Sie unter: http://codecramp.com / java-8-streams-api-convert-Liste-map /

wie schon gesagt, in Java-8 wir die kurze Lösung von Collectors haben:

  list.stream().collect(
         groupingBy(Item::getKey)
        )

und auch können Sie nisten mehrere Gruppe eine andere groupingBy Verfahren als zweiter Parameter übergeben:

  list.stream().collect(
         groupingBy(Item::getKey, groupingBy(Item::getOtherKey))
        )

Auf diese Weise werden wir Multi-Level-Karte haben, wie diese: Map<key, Map<key, List<Item>>>

Ein Java 8 Beispiel einen List<?> von Objekten in eine Map<k, v> zu konvertieren:

List<Hosting> list = new ArrayList<>();
list.add(new Hosting(1, "liquidweb.com", new Date()));
list.add(new Hosting(2, "linode.com", new Date()));
list.add(new Hosting(3, "digitalocean.com", new Date()));

//example 1
Map<Integer, String> result1 = list.stream().collect(
    Collectors.toMap(Hosting::getId, Hosting::getName));

System.out.println("Result 1 : " + result1);

//example 2
Map<Integer, String> result2 = list.stream().collect(
    Collectors.toMap(x -> x.getId(), x -> x.getName()));

-Code kopiert aus:
https://www.mkyong.com/java8/java -8-convert-Liste-to-map /

Ich mag Kango_V Antwort, aber ich denke, es ist zu komplex ist. Ich denke, das ist einfacher - vielleicht zu einfach. Wenn geneigt, könnten Sie String mit einem generischen Marker ersetzen, und machen es für jeden Schlüsseltyp arbeiten.

public static <E> Map<String, E> convertListToMap(Collection<E> sourceList, ListToMapConverterInterface<E> converterInterface) {
    Map<String, E> newMap = new HashMap<String, E>();
    for( E item : sourceList ) {
        newMap.put( converterInterface.getKeyForItem( item ), item );
    }
    return newMap;
}

public interface ListToMapConverterInterface<E> {
    public String getKeyForItem(E item);
}

wie folgt verwendet:

        Map<String, PricingPlanAttribute> pricingPlanAttributeMap = convertListToMap( pricingPlanAttributeList,
                new ListToMapConverterInterface<PricingPlanAttribute>() {

                    @Override
                    public String getKeyForItem(PricingPlanAttribute item) {
                        return item.getFullName();
                    }
                } );

Apache Commons MapUtils.populateMap

Wenn Sie 8 verwenden Java nicht und Sie nicht wollen, eine explizite Schleife aus irgendeinem Grund verwenden, versuchen MapUtils.populateMap von Apache Commons.

MapUtils.populateMap

Angenommen, Sie haben eine Liste von Pairs.

List<ImmutablePair<String, String>> pairs = ImmutableList.of(
    new ImmutablePair<>("A", "aaa"),
    new ImmutablePair<>("B", "bbb")
);

Und Sie wollen jetzt eine Karte des Schlüssels des Pair zum Pair Objekt.

Map<String, Pair<String, String>> map = new HashMap<>();
MapUtils.populateMap(map, pairs, new Transformer<Pair<String, String>, String>() {

  @Override
  public String transform(Pair<String, String> input) {
    return input.getKey();
  }
});

System.out.println(map);

gibt Ausgang:

{A=(A,aaa), B=(B,bbb)}

Das wird gesagt, eine for Schleife ist vielleicht leichter zu verstehen. (Diese unten gibt die gleiche Ausgabe):

Map<String, Pair<String, String>> map = new HashMap<>();
for (Pair<String, String> pair : pairs) {
  map.put(pair.getKey(), pair);
}
System.out.println(map);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top