How do I keep the iteration order of a List when using Collections.toMap() on a stream?

前端 未结 4 2023
自闭症患者
自闭症患者 2020-11-27 15:31

I am creating a Map from a List as follows:

List strings = Arrays.asList(\"a\", \"bb\", \"ccc\");

Map

        
相关标签:
4条回答
  • 2020-11-27 15:59

    The 2-parameter version of Collectors.toMap() uses a HashMap:

    public static <T, K, U> Collector<T, ?, Map<K,U>> toMap(
        Function<? super T, ? extends K> keyMapper, 
        Function<? super T, ? extends U> valueMapper) 
    {
        return toMap(keyMapper, valueMapper, throwingMerger(), HashMap::new);
    }
    

    To use the 4-parameter version, you can replace:

    Collectors.toMap(Function.identity(), String::length)
    

    with:

    Collectors.toMap(
        Function.identity(), 
        String::length, 
        (u, v) -> {
            throw new IllegalStateException(String.format("Duplicate key %s", u));
        }, 
        LinkedHashMap::new
    )
    

    Or to make it a bit cleaner, write a new toLinkedMap() method and use that:

    public class MoreCollectors
    {
        public static <T, K, U> Collector<T, ?, Map<K,U>> toLinkedMap(
            Function<? super T, ? extends K> keyMapper,
            Function<? super T, ? extends U> valueMapper)
        {
            return Collectors.toMap(
                keyMapper,
                valueMapper, 
                (u, v) -> {
                    throw new IllegalStateException(String.format("Duplicate key %s", u));
                },
                LinkedHashMap::new
            );
        }
    }
    
    0 讨论(0)
  • 2020-11-27 16:01

    In Kotlin, toMap() is order-preserving.

    fun <K, V> Iterable<Pair<K, V>>.toMap(): Map<K, V>
    

    Returns a new map containing all key-value pairs from the given collection of pairs.

    The returned map preserves the entry iteration order of the original collection. If any of two pairs would have the same key the last one gets added to the map.

    Here's its implementation:

    public fun <K, V> Iterable<Pair<K, V>>.toMap(): Map<K, V> {
        if (this is Collection) {
            return when (size) {
                0 -> emptyMap()
                1 -> mapOf(if (this is List) this[0] else iterator().next())
                else -> toMap(LinkedHashMap<K, V>(mapCapacity(size)))
            }
        }
        return toMap(LinkedHashMap<K, V>()).optimizeReadOnlyMap()
    }
    

    The usage is simply:

    val strings = listOf("a", "bb", "ccc")
    val map = strings.map { it to it.length }.toMap()
    

    The underlying collection for map is a LinkedHashMap (which is insertion-ordered).

    0 讨论(0)
  • 2020-11-27 16:09

    Simple function to map array of objects by some field:

    public static <T, E> Map<E, T> toLinkedHashMap(List<T> list, Function<T, E> someFunction) {
        return list.stream()
                   .collect(Collectors.toMap(
                       someFunction, 
                       myObject -> myObject, 
                       (key1, key2) -> key1, 
                       LinkedHashMap::new)
                   );
    }
    
    
    Map<String, MyObject> myObjectsByIdMap1 = toLinkedHashMap(
                    listOfMyObjects, 
                    MyObject::getSomeStringField()
    );
    
    Map<Integer, MyObject> myObjectsByIdMap2 = toLinkedHashMap(
                    listOfMyObjects, 
                    MyObject::getSomeIntegerField()
    );
    
    0 讨论(0)
  • 2020-11-27 16:21

    Provide your own Supplier, Accumulator and Combiner:

        List<String> myList = Arrays.asList("a", "bb", "ccc"); 
        // or since java 9 List.of("a", "bb", "ccc");
        
        LinkedHashMap<String, Integer> mapInOrder = myList
            .stream()
            .collect(
                LinkedHashMap::new,                                   // Supplier
                (map, item) -> map.put(item, item.length()),          // Accumulator
                Map::putAll);                                         // Combiner
    
        System.out.println(mapInOrder);  // {a=1, bb=2, ccc=3}
    
    0 讨论(0)
提交回复
热议问题