किसी स्ट्रीम पर Collections.toMap () का उपयोग करते समय मैं एक सूची के पुनरावृत्ति क्रम को कैसे रखूं?


84

मैं इस प्रकार Mapसे एक बना रहा हूँ List:

List<String> strings = Arrays.asList("a", "bb", "ccc");

Map<String, Integer> map = strings.stream()
    .collect(Collectors.toMap(Function.identity(), String::length));

मैं उसी पुनरावृत्ति क्रम को रखना चाहता हूं जैसा कि में था List। मैं विधियों LinkedHashMapका उपयोग करके कैसे बना सकता हूं Collectors.toMap()?


1
कृपया नीचे मेरे उत्तर की जाँच करें। यह एक कस्टम का उपयोग कर कोड के केवल 4 लाइनों है Supplier, Accumulatorऔर Combinerके लिए collectअपने की विधि stream:)
hzitoun

1
प्रश्न का पहले ही उत्तर दिया जा चुका है, मैं अभी इस प्रश्न का उत्तर खोजने का मार्ग बनाना चाहता हूं। (1) आप मानचित्र में आदेश चाहते हैं, आपको LinkedHashMap (2) कलेक्टर का उपयोग करना होगा। मैप () में कई कार्यान्वयन हैं, जिनमें से एक जो एक मानचित्र के लिए पूछता है। इसलिए LinkedHashMap का उपयोग करें जहां यह मानचित्र की अपेक्षा करता है।
सत्येंद्र कुमार

जवाबों:


120

के 2 पैरामीटर संस्करणCollectors.toMap() एक का उपयोग करता है 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);
}

4-पैरामीटर संस्करण का उपयोग करने के लिए , आप प्रतिस्थापित कर सकते हैं:

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

साथ में:

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

या इसे थोड़ा साफ करने के लिए, एक नई toLinkedMap()विधि लिखें और उसका उपयोग करें:

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

2
ऐसी जटिलता क्यों? आप आसानी से ऐसा कर सकते हैं, नीचे मेरे उत्तर की जांच करें
hzitoun

1
mergeFunction4-पैरामीटर संस्करण Collectors.toMap()में कोई सुराग नहीं है कि किस कुंजी को मर्ज किया जा रहा है, दोनों uऔर vमान हैं। इसलिए IllegalStateException के बारे में यह संदेश सही नहीं है।
MoonFruit

1
@hzitoun क्योंकि यदि आप बस उपयोग करते हैं Map::put, तो आप एक ही कुंजी के लिए (संभवतः) विभिन्न मूल्यों के साथ समाप्त होते हैं। का उपयोग करके Map::put, आपने अप्रत्यक्ष रूप से चुना है कि आपके द्वारा पहला मूल्य गलत है। क्या वह अंत-उपयोगकर्ता चाहता है? क्या आपको यकीन है? यदि हाँ, तो सुनिश्चित करें, उपयोग करें Map::put। अन्यथा, आप निश्चित नहीं हैं और यह तय नहीं कर सकते हैं: उपयोगकर्ता को बताएं कि उनकी धारा विभिन्न मूल्यों के साथ दो समान कुंजी के लिए मैप की गई है। मैंने आपके ही जवाब पर टिप्पणी की होगी, लेकिन यह फिलहाल बंद है।
ओलिवियर ग्राएगोइरे

70

अपना खुद का Supplier, Accumulatorऔर 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}

1
@ सुशील स्वीकृत उत्तर तर्क का पुन: उपयोग करने की अनुमति देता है
सिलेंडर।

1
धारा साइड-इफेक्ट्स पर निर्भर करती है जैसे कि map.put(..)गलत है।
निकोलस चारलाम्बिदिस

क्या आप जानते हैं कि तेज क्या है? अपने संस्करण या स्वीकृत उत्तर का उपयोग करना?
निमो

@ निकोलस आप कृपया बता सकते हैं कि साइड इफेक्ट्स से आपका क्या मतलब है ? मुझे वास्तव में यह तय करने की समस्या है कि
किसे

0

कोटलिन में, toMap()ऑर्डर-संरक्षण है।

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

जोड़े के दिए गए संग्रह से सभी मुख्य-मूल्य वाले जोड़े एक नया नक्शा लौटाता है।

लौटा हुआ नक्शा मूल संग्रह के प्रवेश पुनरावृत्ति क्रम को संरक्षित करता है। यदि दो में से किसी भी जोड़े में एक ही कुंजी होगी तो अंतिम को नक्शे में जोड़ा जाएगा।

यहाँ इसका कार्यान्वयन है:

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

उपयोग बस है:

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

के लिए अंतर्निहित संग्रह mapएक LinkedHashMap(जो प्रविष्टि-आदेश दिया गया है) है।


0

कुछ क्षेत्र द्वारा वस्तुओं की सारणी को मैप करने का सरल कार्य:

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()
);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.