代码之家  ›  专栏  ›  技术社区  ›  Rachel

Java:如何将列表转换为映射

  •  180
  • Rachel  · 技术社区  · 14 年前

    最近我和一位同事讨论了什么是转换的最佳方式 List Map 在Java中,如果这样做有什么特别的好处的话。

    我想知道最佳转换方法,如果有人能指导我,我将非常感激。

    List<Object[]> results;
    Map<Integer, String> resultsMap = new HashMap<Integer, String>();
    for (Object[] o : results) {
        resultsMap.put((Integer) o[0], (String) o[1]);
    }
    
    17 回复  |  直到 6 年前
        1
  •  184
  •   Maytham Fahmi    7 年前
    List<Item> list;
    Map<Key,Item> map = new HashMap<Key,Item>();
    for (Item i : list) map.put(i.getKey(),i);
    

    当然,假设每个项目都有 getKey()

        2
  •  288
  •   Alexis C.    8 年前

    ,您可以在一行中使用 streams Collectors 上课。

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

    简短演示:

    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 + "]";
        }
    }
    

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

    如注释中所述,您可以使用 Function.identity() 而不是 item -> item i -> i 相当明确。

    完整地说,如果函数不是双射的,可以使用二进制运算符。例如,让我们考虑一下 List 以及映射函数,对于一个int值,计算其模3的结果:

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

    java.lang.IllegalStateException: Duplicate key 1 . 这是因为1%3与4%3相同,因此给定密钥映射函数时具有相同的密钥值。在这种情况下,您可以提供合并运算符。

    这里有一个值的总和; (i1, i2) -> i1 + i2; Integer::sum .

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

    现在输出:

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

    希望有帮助!:)

        3
  •  115
  •   Community CDub    7 年前

    the right answer is to use Google Collections :

    Map<String,Role> mappedRoles = Maps.uniqueIndex(yourList, new Function<Role,String>() {
      public String apply(Role from) {
        return from.getName(); // or something else
      }});
    
        4
  •  15
  •   Community CDub    7 年前

    自Java 8以来 answer by @ZouZou 使用 Collectors.toMap 收集器无疑是解决这个问题的惯用方法。

    由于这是一个非常常见的任务,我们可以将它变成一个静态实用程序。

    这样,解决方案就真正变成了一行代码。

    /**
     * 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()));
    }
    

    List<Student> :

    Map<Long, Student> studentsById = toMapBy(students, Student::getId);
    
        5
  •  13
  •   stackFan    7 年前

    使用Java 8,您可以执行以下操作:

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

    Value

        6
  •  10
  •   Steve Kuo    13 年前

    一个 List Map 在概念上是不同的。一个 列表 地图 具有映射到键的值。每个键只能指向一个值。

    列表 的项,可以将其转换为 地图 的项目没有重复项?每个项目都有唯一的密钥吗?如果是这样的话就可以把它们放在 地图 .

        7
  •  8
  •   Frank Neblung    5 年前
        8
  •  7
  •   akhil_mittal    7 年前

    爪哇8 使用方法 toMap(keyMapper, valueMapper) . 根据 doc 对于此方法实现:

    对于类型、可变性、可序列化性或

    如果我们对 Map 接口,例如。 HashMap 然后我们可以使用重载表单:

    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
    

    Function.identity() i->i 函数.标识() 而不是 i -> i 可能会节省一些内存 answer .

        9
  •  5
  •   xxf    13 年前

    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);
    }
    
        10
  •  4
  •   Vitaliy Oliynyk    9 年前

    如果没有java-8,您将能够在一行Commons集合和Closure类中执行此操作

    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);
            }
        });
    }};
    
        11
  •  2
  •   Daniel    14 年前

    根据你想要达到的目标,你会想到很多解决方案:

    每个列表项都是键和值

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

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

    列表元素可以查找,但不能保证它们是唯一的:使用google MultiMaps

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

    将所有元素的位置作为关键:

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

    这真的取决于你想得到什么。

    从示例中可以看到,映射是从键到值的映射,而列表只是一系列元素,每个元素都有一个位置。所以它们根本不能自动转换。

        12
  •  2
  •   Kango_V    13 年前

    这里有一个小方法,我写正是为了这个目的。它使用来自Apache Commons的Validate。

    请随意使用。

    /**
     * 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;
    }
    
        13
  •  2
  •   EMM    7 年前

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

    有关详细信息,请访问: http://codecramp.com/java-8-streams-api-convert-list-map/

        14
  •  2
  •   Andrea Scarafoni    6 年前

    如前所述,在java-8中,我们有一个由收集器提供的简明解决方案:

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

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

    这样,我们就有了多层次的地图,比如: Map<key, Map<key, List<Item>>>

        15
  •  1
  •   Pang Ajmal PraveeN    7 年前

    一个Java8示例来转换 List<?> Map<k, v> :

    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()));
    

    代码复制自:
    https://www.mkyong.com/java8/java-8-convert-list-to-map/

        16
  •  0
  •   cs94njw    13 年前

    我喜欢康戈夫的回答,但我觉得太复杂了。我觉得这更简单-也许太简单了。如果愿意,可以用泛型标记替换字符串,并使其适用于任何键类型。

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

    像这样使用:

            Map<String, PricingPlanAttribute> pricingPlanAttributeMap = convertListToMap( pricingPlanAttributeList,
                    new ListToMapConverterInterface<PricingPlanAttribute>() {
    
                        @Override
                        public String getKeyForItem(PricingPlanAttribute item) {
                            return item.getFullName();
                        }
                    } );
    
        17
  •  0
  •   typoerrpr    7 年前

    如果您不使用Java 8并且出于某种原因不想使用显式循环,请尝试 MapUtils.populateMap 来自Apache Commons。

    MapUtils.populateMap

    Pair s。

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

    一对 一对

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

    输出:

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

    这么说吧,a for 循环也许更容易理解。(以下输出相同):

    Map<String, Pair<String, String>> map = new HashMap<>();
    for (Pair<String, String> pair : pairs) {
      map.put(pair.getKey(), pair);
    }
    System.out.println(map);
    
        18
  •  0
  •   Ankit Sharma    5 年前

    results.stream().collect(Collectors.toMap(e->((Integer)e[0]), e->(String)e[1]));