जावा 8 सूची <V> मानचित्र में <K, V>


932

मैं जावा 8 स्ट्रीम और लैम्ब्डा का उपयोग करके वस्तुओं की सूची को मैप में अनुवाद करना चाहता हूं।

यह है कि मैं इसे जावा 7 और नीचे कैसे लिखूंगा।

private Map<String, Choice> nameMap(List<Choice> choices) {
        final Map<String, Choice> hashMap = new HashMap<>();
        for (final Choice choice : choices) {
            hashMap.put(choice.getName(), choice);
        }
        return hashMap;
}

मैं जावा 8 और अमरूद का उपयोग करके इसे आसानी से पूरा कर सकता हूं लेकिन मैं यह जानना चाहूंगा कि अमरूद के बिना यह कैसे किया जा सकता है।

अमरूद में:

private Map<String, Choice> nameMap(List<Choice> choices) {
    return Maps.uniqueIndex(choices, new Function<Choice, String>() {

        @Override
        public String apply(final Choice input) {
            return input.getName();
        }
    });
}

और जावा 8 लैम्ब्डा के साथ अमरूद।

private Map<String, Choice> nameMap(List<Choice> choices) {
    return Maps.uniqueIndex(choices, Choice::getName);
}

जवाबों:


1394

Collectorsप्रलेखन के आधार पर यह उतना ही सरल है:

Map<String, Choice> result =
    choices.stream().collect(Collectors.toMap(Choice::getName,
                                              Function.identity()));

167
साइड नोट के रूप में, Java 8 के बाद भी, JDK अभी भी संक्षिप्त प्रतियोगिता में प्रतिस्पर्धा नहीं कर सकता है। अमरूद का विकल्प इतना पठनीय लगता है Maps.uniqueIndex(choices, Choice::getName):।
बोगदान कैलमैक

3
JOOL लाइब्रेरी से ( स्टेटिकली इम्पोर्टेड) ​​का उपयोग करना ( जो कि मैं जावा 8 का उपयोग करके किसी Seqको सुझाऊंगा ), आप इसके साथ संक्षिप्तता में भी सुधार कर सकते हैं: seq(choices).toMap(Choice::getName)
lukens

5
क्या फंक्शन.सिटी का उपयोग करने से कोई लाभ है? मेरा मतलब है, यह -> यह छोटा है
shabunc

9
@ शबनम मैं किसी भी लाभ के बारे में नहीं जानता और वास्तव में it -> itखुद का उपयोग करता हूं। Function.identity()इसका उपयोग यहाँ ज्यादातर इसलिए किया जाता है क्योंकि इसका उपयोग संदर्भित दस्तावेज में किया गया है और यह सब मुझे लिखने के समय के
लंबोदर के

12
@ ज़ापल, ओह, वास्तव में यह पता चला है कि इसके पीछे कारण हैं - stackoverflow.com/questions/28032827/…
shabunc

307

यदि आपकी कुंजी सूची में सभी तत्वों के लिए विशिष्ट होने की गारंटी नहीं है , तो आपको इसे ए के Map<String, List<Choice>>बजाय परिवर्तित करना चाहिएMap<String, Choice>

Map<String, List<Choice>> result =
 choices.stream().collect(Collectors.groupingBy(Choice::getName));

76
यह वास्तव में आपको मैप देता है <स्ट्रिंग, सूची <विकल्प >> जो गैर-अद्वितीय कुंजी की संभावना से संबंधित है, लेकिन वह नहीं है जो ओपी ने अनुरोध किया है। अमरूद में, Multimaps.index (विकल्प, विकल्प :: getName) शायद एक बेहतर विकल्प है यदि आप किसी भी तरह से यह चाहते हैं।
रिचर्ड निकोल्स

या इसके बजाय अमरूद के मल्टीमैप <स्ट्रिंग, चॉइस> का उपयोग करें, जो उन परिदृश्यों में काफी काम आता है जहां एक ही मानचित्र में कई मान होते हैं। अमरुद में विभिन्न उपयोगिता विधियाँ उपलब्ध हैं जैसे मानचित्र <स्ट्रिंग, सूची <विकल्प >> बनाने के बजाय ऐसी डेटा संरचनाओं का उपयोग करने के लिए
नीरज बी।

1
@RichardNichols क्यों अमरूद Multimapsविधि एक बेहतर विकल्प है? चूंकि यह किसी Mapवस्तु को वापस नहीं करता है इसलिए यह एक असुविधा हो सकती है ।
वेव

156

getName()कुंजी के रूप में और Choiceमानचित्र के मूल्य के रूप में उपयोग करें :

Map<String, Choice> result =
    choices.stream().collect(Collectors.toMap(Choice::getName, c -> c));

19
कृपया कुछ विवरण लिखें ताकि उपयोगकर्ता समझ सके।
मयंक जैन

4
यह वास्तव में बहुत बुरा है, यहाँ अधिक विवरण नहीं है, क्योंकि मुझे यह उत्तर सबसे अच्छा लगता है।
MadConan

Collectors.toMap(Choice::getName,c->c)(2
चार्ट

7
यह choices.stream().collect(Collectors.toMap(choice -> choice.getName(),choice -> choice)); कुंजी के लिए पहले फ़ंक्शन के बराबर है , मान के लिए दूसरा फ़ंक्शन
वॉटरकार

16
मुझे पता है कि यह देखना और समझना कितना आसान है c -> cलेकिन Function.identity()अधिक अर्थ संबंधी जानकारी देता है। मैं आमतौर पर एक स्थैतिक आयात का उपयोग करता हूं ताकि मैं बस उपयोग कर identity()
हांक डी

28

यदि आप कलेक्टरों का उपयोग नहीं करना चाहते हैं, तो यहां एक और जानकारी दी गई है।

Map<String, Choice> result =
   choices.stream().collect(HashMap<String, Choice>::new, 
                           (m, c) -> m.put(c.getName(), c),
                           (m, u) -> {});

1
जैसा Collectors.toMap()कि आपने ऊपर उदाहरण में दिखाया है, तब या हमारे अपने HashMap का उपयोग करना बेहतर है ?
स्वप्निल गंगराड़े

1
इस उदाहरण ने उदाहरण दिया कि मानचित्र में कुछ और कैसे रखा जाए। मैं एक विधि कॉल द्वारा प्रदान नहीं किया गया मान चाहता था। धन्यवाद!
th3morg

1
तीसरा तर्क फ़ंक्शन सही नहीं है। वहाँ आपको दो हश्मप्स को मर्ज करने के लिए कुछ फंक्शन प्रदान करना चाहिए, कुछ हशमैप :: putAll
jesantana

25

सूचीबद्ध अधिकांश उत्तर, उस मामले को याद करते हैं जब सूची में डुप्लिकेट आइटम हैं । उस मामले में जवाब फेंक देंगे IllegalStateExceptionसूची डुप्लिकेट को संभालने के लिए नीचे दिए गए कोड को भी देखें:

public Map<String, Choice> convertListToMap(List<Choice> choices) {
    return choices.stream()
        .collect(Collectors.toMap(Choice::getName, choice -> choice,
            (oldValue, newValue) -> newValue));
  }

19

सरल तरीके से एक और विकल्प

Map<String,Choice> map = new HashMap<>();
choices.forEach(e->map.put(e.getName(),e));

3
इस या जावा 7 प्रकार का उपयोग करने में कोई व्यावहारिक अंतर नहीं है।
आशीष लोहिया

3
मुझे यह पढ़ने और समझने में आसानी हुई कि अन्य तंत्रों की तुलना में क्या चल रहा था
Freiheit

2
एसओ ने जावा 8 स्ट्रीम के साथ पूछा।
मेहराज मलिक

18

उदाहरण के लिए, यदि आप ऑब्जेक्ट फ़ील्ड को मानचित्र में बदलना चाहते हैं:

उदाहरण वस्तु:

class Item{
        private String code;
        private String name;

        public Item(String code, String name) {
            this.code = code;
            this.name = name;
        }

        //getters and setters
    }

और ऑपरेशन सूची को मानचित्र में बदलें:

List<Item> list = new ArrayList<>();
list.add(new Item("code1", "name1"));
list.add(new Item("code2", "name2"));

Map<String,String> map = list.stream()
     .collect(Collectors.toMap(Item::getCode, Item::getName));

12

यदि आप तृतीय पक्ष पुस्तकालयों का उपयोग करने में कोई आपत्ति नहीं करते हैं, तो एओएल के साइक्लोप्स-रिएक्शन लिबास (खुलासा मैं एक योगदानकर्ता हूं) के पास सूची और मानचित्र सहित सभी जेडीके संग्रह प्रकारों के लिए एक्सटेंशन हैं ।

ListX<Choices> choices;
Map<String, Choice> map = choices.toMap(c-> c.getName(),c->c);

10

मैं ऐसा करने की कोशिश कर रहा था और पाया कि, ऊपर के उत्तरों का उपयोग करते हुए, जब Functions.identity()मानचित्र की कुंजी का उपयोग कर रहा था, तो मेरे पास स्थानीय पद्धति का उपयोग करने के साथ समस्याएँ थीं जैसे this::localMethodNameकि वास्तव में टाइपिंग मुद्दों के कारण काम करना।

Functions.identity()वास्तव में इस मामले में टाइपिंग करने के लिए कुछ करता है, इसलिए यह विधि केवल वापस लौटकर Objectऔर के एक मान को स्वीकार करके काम करेगीObject

इसे हल करने के लिए, मैंने इसके बजाय खाई Functions.identity()और उपयोग को समाप्त कर s->sदिया।

इसलिए मेरा कोड, मेरे मामले में एक निर्देशिका के अंदर सभी निर्देशिकाओं को सूचीबद्ध करने के लिए, और प्रत्येक के लिए नक्शे की कुंजी के रूप में निर्देशिका के नाम का उपयोग करें और फिर निर्देशिका नाम के साथ एक विधि को कॉल करें और आइटमों का एक संग्रह लौटाएं, ऐसा लगता है:

Map<String, Collection<ItemType>> items = Arrays.stream(itemFilesDir.listFiles(File::isDirectory))
.map(File::getName)
.collect(Collectors.toMap(s->s, this::retrieveBrandItems));

10

आप एक इंटस्ट्रीम का उपयोग करके सूचकांकों की एक स्ट्रीम बना सकते हैं और फिर उन्हें मैप में बदल सकते हैं:

Map<Integer,Item> map = 
IntStream.range(0,items.size())
         .boxed()
         .collect(Collectors.toMap (i -> i, i -> items.get(i)));

1
यह एक अच्छा विकल्प नहीं है क्योंकि आप प्रत्येक तत्व के लिए एक कॉल () कॉल करते हैं, इसलिए ऑपरेशन की जटिलता को बढ़ाते हैं (ओ (एन * के) यदि आइटम एक हैशमप है)।
निकोलस नोबेलिस

एक हैशाप ओ (1) पर (i) नहीं मिलता है?
Ivo van der Veeken

@ स्नवेंडर कोड स्निपेट में प्राप्त (i) सूची में है, न कि नक्शे पर।
जकी

@ जाकी मैं निकोलस की टिप्पणी के बारे में बात कर रहा था। यदि आइटम की सूची के बजाय हैशमैप है, तो मुझे n * k जटिलता दिखाई नहीं देती है।
इवो ​​वैन डेर विकेन

8

मैं लिखूंगा कि जेनरिक और नियंत्रण के उलट का उपयोग करके सूची को मानचित्र में कैसे परिवर्तित किया जाए । बस सार्वभौमिक विधि!

शायद हमारे पास इंटेगर की सूची या वस्तुओं की सूची है तो सवाल निम्नलिखित है: नक्शे की कुंजी क्या होनी चाहिए ?

इंटरफ़ेस बनाएँ

public interface KeyFinder<K, E> {
    K getKey(E e);
}

अब नियंत्रण का उलटा उपयोग कर:

  static <K, E> Map<K, E> listToMap(List<E> list, KeyFinder<K, E> finder) {
        return  list.stream().collect(Collectors.toMap(e -> finder.getKey(e) , e -> e));
    }

उदाहरण के लिए, यदि हमारे पास पुस्तक की वस्तुएं हैं, तो यह वर्ग मानचित्र के लिए कुंजी चुनना है

public class BookKeyFinder implements KeyFinder<Long, Book> {
    @Override
    public Long getKey(Book e) {
        return e.getPrice()
    }
}



4

इसे 2 तरीकों से किया जा सकता है। जिस व्यक्ति को हम प्रदर्शित करने जा रहे हैं, उसे कक्षा में आने दें।

public class Person {

    private String name;
    private int age;

    public String getAge() {
        return age;
    }
}

चलो व्यक्तियों व्यक्तियों की सूची हो नक्शा करने के लिए परिवर्तित किया

1. सूची पर सरल foreach और एक लैम्ब्डा अभिव्यक्ति का उपयोग करना

Map<Integer,List<Person>> mapPersons = new HashMap<>();
persons.forEach(p->mapPersons.put(p.getAge(),p));

स्ट्रीम पर 2.Using कलेक्टरों को दी गई सूची में परिभाषित किया गया है।

 Map<Integer,List<Person>> mapPersons = 
           persons.stream().collect(Collectors.groupingBy(Person::getAge));

4

ऐसा करने के लिए धाराओं का उपयोग करना संभव है। स्पष्ट रूप से उपयोग करने की आवश्यकता को दूर करने के लिए Collectors, toMapसांख्यिकीय रूप से आयात करना संभव है (जैसा कि प्रभावी जावा, तीसरे संस्करण द्वारा अनुशंसित)।

import static java.util.stream.Collectors.toMap;

private static Map<String, Choice> nameMap(List<Choice> choices) {
    return choices.stream().collect(toMap(Choice::getName, it -> it));
}


3
Map<String,Choice> map=list.stream().collect(Collectors.toMap(Choice::getName, s->s));

यहां तक ​​कि मेरे लिए इस उद्देश्य को पूरा करता है,

Map<String,Choice> map=  list1.stream().collect(()-> new HashMap<String,Choice>(), 
            (r,s) -> r.put(s.getString(),s),(r,s) -> r.putAll(s));

3

यदि एक ही कुंजी नाम के लिए हर नए मूल्य को ओवरराइड किया जाना है:

public Map < String, Choice > convertListToMap(List < Choice > choices) {
    return choices.stream()
        .collect(Collectors.toMap(Choice::getName,
            Function.identity(),
            (oldValue, newValue) - > newValue));
}

यदि सभी विकल्पों को नाम के लिए सूची में समूहीकृत किया जाना है:

public Map < String, Choice > convertListToMap(List < Choice > choices) {
    return choices.stream().collect(Collectors.groupingBy(Choice::getName));
}

1
List<V> choices; // your list
Map<K,V> result = choices.stream().collect(Collectors.toMap(choice::getKey(),choice));
//assuming class "V" has a method to get the key, this method must handle case of duplicates too and provide a unique key.


-1
String array[] = {"ASDFASDFASDF","AA", "BBB", "CCCC", "DD", "EEDDDAD"};
    List<String> list = Arrays.asList(array);
    Map<Integer, String> map = list.stream()
            .collect(Collectors.toMap(s -> s.length(), s -> s, (x, y) -> {
                System.out.println("Dublicate key" + x);
                return x;
            },()-> new TreeMap<>((s1,s2)->s2.compareTo(s1))));
    System.out.println(map);

DIBATE कुंजी AA {12 = ASDFASDFASDF, 7 = EEDDDAD, 4 = CCCC, 3 = BBB, 2 = AA}


2
आप यहाँ क्या करने की कोशिश कर रहे हैं ?? क्या आपने प्रश्न पढ़ा है?
19
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.