जावा 8 में मैं एक लैम्बडा का उपयोग करके एक मानचित्र <K, V> को दूसरे मानचित्र <K, V> में कैसे परिवर्तित करूं?


140

मैंने अभी-अभी जावा 8 को देखना शुरू किया है और लैंबडास को आज़माने के लिए मैंने सोचा कि मैं हाल ही में लिखी गई एक बहुत ही साधारण बात को फिर से लिखने की कोशिश करूँगा। मुझे स्ट्रिंग के एक मैप को कॉलम के दूसरे मैप में कॉलम में बदलने की आवश्यकता है जहां नए मैप में कॉलम पहले मैप में कॉलम की एक डिफेंसिव कॉपी है। कॉलम में एक कॉपी कंस्ट्रक्टर है। अब तक मुझे जो निकटतम मिला है वह है:

    Map<String, Column> newColumnMap= new HashMap<>();
    originalColumnMap.entrySet().stream().forEach(x -> newColumnMap.put(x.getKey(), new Column(x.getValue())));

लेकिन मुझे यकीन है कि ऐसा करने के लिए एक अच्छा तरीका होना चाहिए और मैं कुछ सलाह के लिए आभारी रहूंगा।

जवाबों:


222

आप एक कलेक्टर का उपयोग कर सकते हैं :

import java.util.*;
import java.util.stream.Collectors;

public class Defensive {

  public static void main(String[] args) {
    Map<String, Column> original = new HashMap<>();
    original.put("foo", new Column());
    original.put("bar", new Column());

    Map<String, Column> copy = original.entrySet()
        .stream()
        .collect(Collectors.toMap(Map.Entry::getKey,
                                  e -> new Column(e.getValue())));

    System.out.println(original);
    System.out.println(copy);
  }

  static class Column {
    public Column() {}
    public Column(Column c) {}
  }
}

6
मुझे लगता है कि उपरोक्त में ध्यान देने वाली महत्वपूर्ण (और मामूली जवाबी) बात यह है कि परिवर्तन कलेक्टर में होता है, बजाय एक नक्शे () स्ट्रीम ऑपरेशन में
ब्रायन एग्न्यू

24
Map<String, Integer> map = new HashMap<>();
map.put("test1", 1);
map.put("test2", 2);

Map<String, Integer> map2 = new HashMap<>();
map.forEach(map2::put);

System.out.println("map: " + map);
System.out.println("map2: " + map2);
// Output:
// map:  {test2=2, test1=1}
// map2: {test2=2, test1=1}

आप जो चाहें वह करने के लिए forEachविधि का उपयोग कर सकते हैं।

आप वहां क्या कर रहे हैं:

map.forEach(new BiConsumer<String, Integer>() {
    @Override
    public void accept(String s, Integer integer) {
        map2.put(s, integer);     
    }
});

जिसे हम लंबोदर में सरल बना सकते हैं:

map.forEach((s, integer) ->  map2.put(s, integer));

और क्योंकि हम सिर्फ एक मौजूदा पद्धति को कॉल कर रहे हैं, हम एक विधि संदर्भ का उपयोग कर सकते हैं , जो हमें देता है:

map.forEach(map2::put);

8
मुझे पसंद है कि आपने यहाँ के दृश्यों के पीछे क्या-क्या समझाया है, यह बहुत स्पष्ट करता है। लेकिन मुझे लगता है कि बस मुझे अपने मूल नक्शे की एक सीधी प्रतिलिपि देता है, न कि एक नया मानचित्र जहां मानों को रक्षात्मक प्रतियों में बदल दिया गया है। क्या मैं आपको सही ढंग से समझ रहा हूं कि जिस कारण से हम सिर्फ उपयोग कर सकते हैं (map2 :: put) वह यह है कि वही तर्क लंबोदर में जा रहे हैं, उदाहरण के लिए पुट विधि में जा रहे हैं? तो एक रक्षात्मक प्रतिलिपि बनाने के लिए इसे करने की आवश्यकता होगी originalColumnMap.forEach((string, column) -> newColumnMap.put(string, new Column(column)));या क्या मैं इसे छोटा कर सकता हूं?
annesadleir

हाँ तुम हो। यदि आप केवल उन्हीं तर्कों में गुजर रहे हैं, तो आप एक विधि संदर्भ का उपयोग कर सकते हैं, हालांकि इस मामले में, चूंकि आपके पास new Column(column)एक पैरेमीटर है, इसलिए आपको इसके साथ जाना होगा।
Arrem

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

इस तरह के जवाब की बात समझने के लिए निश्चित नहीं है। यह एक मौजूदा नक्शे से ज्यादातर सभी मानचित्र कार्यान्वयन के निर्माता पुनर्लेखन है - जैसे यह
किन्नोलियन

13

नए नक्शे में सभी प्रविष्टियों को फिर से सम्मिलित किए बिना जिस तरह से सबसे तेज़ होना चाहिए वह नहीं होगा क्योंकि यह HashMap.cloneआंतरिक रूप से भी पुनः प्रदर्शन करता है।

Map<String, Column> newColumnMap = originalColumnMap.clone();
newColumnMap.replaceAll((s, c) -> new Column(c));

यह करने के लिए एक बहुत ही पठनीय तरीका है और काफी संक्षिप्त है। ऐसा लगता है कि HashMap.clone () भी है Map<String,Column> newColumnMap = new HashMap<>(originalColumnMap);। मुझे नहीं पता कि यह कवर के तहत कोई अलग है।
एनासाडेलिर

2
इस दृष्टिकोण को Mapकार्यान्वयन के व्यवहार को बनाए रखने का लाभ है , अर्थात यदि Mapएक EnumMapया एक है SortedMap, तो परिणाम भी Mapहोगा। SortedMapएक विशेष के मामले में Comparatorयह एक बड़ा शब्दार्थ अंतर कर सकता है। ओह ठीक है, एक ही लागू होता है IdentityHashMap...
Holger

8

इसे सरल रखें और जावा 8 का उपयोग करें: -

 Map<String, AccountGroupMappingModel> mapAccountGroup=CustomerDAO.getAccountGroupMapping();
 Map<String, AccountGroupMappingModel> mapH2ToBydAccountGroups = 
              mapAccountGroup.entrySet().stream()
                         .collect(Collectors.toMap(e->e.getValue().getH2AccountGroup(),
                                                   e ->e.getValue())
                                  );

इस स्थिति में: map.forEach (map2 :: put); सरल है :)
ses

5

यदि आप अपने प्रोजेक्ट में अमरूद (v11 न्यूनतम) का उपयोग करते हैं तो आप मैप्स: ट्रांसफॉर्मवेल्स का उपयोग कर सकते हैं ।

Map<String, Column> newColumnMap = Maps.transformValues(
  originalColumnMap,
  Column::new // equivalent to: x -> new Column(x) 
)

नोट: इस नक्शे के मूल्यों का आलसी मूल्यांकन किया जाता है। यदि रूपांतरण महंगा है, तो आप परिणाम को नए नक्शे में कॉपी कर सकते हैं जैसे कि अमरूद डॉक्स में सुझाए गए।

To avoid lazy evaluation when the returned map doesn't need to be a view, copy the returned map into a new map of your choosing.

नोट: डॉक्स के अनुसार, यह
ऑरिजिनल

सही बात। यदि रूपांतरण महंगा है, तो आप शायद नकल के ओवरहेड के साथ ठीक हैं जो डॉक्स में सुझाए गए नए नक्शे की तरह है। To avoid lazy evaluation when the returned map doesn't need to be a view, copy the returned map into a new map of your choosing.
एंड्रिया बर्गांज़ो

सच है, लेकिन यह उन लोगों के लिए जवाब में एक फुटनोट के रूप में जोड़ने के लायक हो सकता है जो डॉक्स पढ़ना छोड़ देते हैं।
एरिक

@ एरिक बनाता है, बस जोड़ा।
एंड्रिया बर्गांज़ो

3

यहां एक और तरीका है जो आपको एक ही समय में कुंजी और मूल्य तक पहुंच देता है, यदि आपको किसी प्रकार का परिवर्तन करना है।

Map<String, Integer> pointsByName = new HashMap<>();
Map<String, Integer> maxPointsByName = new HashMap<>();

Map<String, Double> gradesByName = pointsByName.entrySet().stream()
        .map(entry -> new AbstractMap.SimpleImmutableEntry<>(
                entry.getKey(), ((double) entry.getValue() /
                        maxPointsByName.get(entry.getKey())) * 100d))
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

1

यदि आप तृतीय पक्ष पुस्तकालयों का उपयोग करने में कोई आपत्ति नहीं करते हैं, तो मेरी साइक्लॉप्स-प्रतिक्रिया एफबीआई में मैप सहित सभी JDK संग्रह प्रकारों के लिए एक्सटेंशन हैं । आप अपने नक्शे को बदलने के लिए सीधे मानचित्र या बिमाप विधियों का उपयोग कर सकते हैं। एक MapX का निर्माण मौजूदा मानचित्र उदा से किया जा सकता है।

  MapX<String, Column> y = MapX.fromMap(orgColumnMap)
                               .map(c->new Column(c.getValue());

यदि आप भी कुंजी को बदलना चाहते हैं तो आप लिख सकते हैं

  MapX<String, Column> y = MapX.fromMap(orgColumnMap)
                               .bimap(this::newKey,c->new Column(c.getValue());

bimap का उपयोग एक ही समय में कुंजियों और मूल्यों को बदलने के लिए किया जा सकता है।

जैसा कि MapX फैली हुई है मैप मैप के रूप में उत्पन्न मानचित्र को भी परिभाषित किया जा सकता है

  Map<String, Column> y
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.