Java:如何将列表转换为地图

最近我和一位同事进行了一次谈话,谈谈在Java中将List转换为Map的最佳方法是什么,以及这样做有什么特别的好处。

我想知道最佳的转换方法,如果有人能指导我,我会很感激。

这是一个好方法:

 List<Object[]> results; Map<Integer, String> resultsMap = new HashMap<Integer, String>(); for (Object[] o : results) { resultsMap.put((Integer) o[0], (String) o[1]); } 
 List<Item> list; Map<Key,Item> map = new HashMap<Key,Item>(); for (Item i : list) map.put(i.getKey(),i); 

当然假设每个Item都有一个getKey()方法,该方法返回正确types的键。

使用java-8 ,您可以使用stream和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 ,尽pipe我发现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来replace。

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

现在输出:

 0 => 9 (ie 3 + 6) 1 => 5 (ie 1 + 4) 2 => 7 (ie 2 + 5) 

希望它有帮助! 🙂

以防万一这个问题不是重复的, 正确的答案是使用Google Collections :

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

从Java 8开始, @ZouZou使用Collectors.toMap器的答案当然是解决这个问题的惯用方法。

由于这是一个普遍的任务,我们可以把它变成一个静态的工具。

这样的解决scheme真正成为一个class轮。

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

还有一个简单的方法,使用Google guava库中的Maps.uniqueIndex(…)来完成此操作

ListMap在概念上是不同的。 List是项目的有序集合。 项目可以包含重复项目,并且项目可能没有任何唯一标识符(关键字)的概念。 一个Map具有映射到键的值。 每个键只能指向一个值。

因此,根据您的List的项目,它可能或不可能将其转换为Map 。 你的List物品没有重复吗? 每个项目是否有唯一的密钥? 如果是这样的话,可以把它们放在Map

通用的方法

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

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

想到许多解决scheme,取决于你想要达到的目标:

每个列表项目是关键和价值

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

这真的取决于你想要达到的目标。

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

这是我为此写的一个小方法。 它使用来自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; } 

您可以利用Java 8的streamAPI。

 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/

我喜欢Kango_V的回答,但我认为这太复杂了。 我觉得这很简单 – 也许太简单了。 如果倾斜,你可以用generics标记replaceString,并使其适用于任何Keytypes。

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

将对象的List<?>转换为Map<k, v>的Java 8示例:

 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/