डुप्लिकेट कुंजियों के साथ नक्शा कार्यान्वयन


116

मैं डुप्लिकेट कुंजी के साथ एक नक्शा है चाहता हूँ।

मुझे पता है कि कई मानचित्र कार्यान्वयन हैं (ग्रहण मुझे 50 के बारे में दिखाता है), इसलिए मुझे यकीन है कि एक होना चाहिए जो इसे अनुमति देता है। मुझे पता है कि ऐसा करने के लिए अपना स्वयं का मानचित्र लिखना आसान है, लेकिन मैं कुछ मौजूदा समाधान का उपयोग करूंगा।

शायद कॉमन्स-संग्रह या गूगल-संग्रह में कुछ?


4
यह कैसे काम करना चाहिए? यदि आप एक कुंजी के साथ जुड़े मूल्य के लिए पूछते हैं, और यह कुंजी नक्शे में कई बार मौजूद है, तो किस मूल्य को वापस किया जाना चाहिए?
मेन्मेंट

अपवाद छोड़ सकते हैं, मुझे इस नक्शे को केवल पुनरावृत्ति के लिए चाहिए।
एडेप्टर

6
यदि आपको केवल पुनरावृत्ति के लिए इसकी आवश्यकता है, तो आपको पहले स्थान पर एक मानचित्र की आवश्यकता क्यों है? जोड़े या कुछ और की एक सूची का उपयोग करें ...
टैल प्रेसमैन

2
क्योंकि मेरा पूरा कार्यक्रम पहले से ही मैप के साथ काम करता है और अब मुझे पता चला है कि डेटा के लिए डुप्लिकेट कुंजी होना संभव है। यदि मानचित्र का अलग-अलग तरीके से उपयोग करना गलत होगा, तो हमारे पास मानचित्र के केवल 5 कार्यान्वयन होंगे और 50+ नहीं।
11

जवाबों:


90

आप एक मल्टीमैप के लिए खोज रहे हैं, और वास्तव में कॉमन्स-संग्रह और अमरूद दोनों के लिए कई कार्यान्वयन हैं। मल्टीपैप कई कुंजी के लिए अनुमति देता है प्रति कुंजी मानों का एक संग्रह बनाए रखने के द्वारा, यानी आप नक्शे में एक ही वस्तु डाल सकते हैं, लेकिन आप एक संग्रह प्राप्त करते हैं।

यदि आप जावा 5 का उपयोग कर सकते हैं, तो मैं अमरूद को पसंद करूंगा Multimapक्योंकि यह जेनरिक-जागरूक है।


3
इसके अलावा, यह मल्टीपैप एक मैप होने का दिखावा नहीं करता है जिस तरह से अपाचे एक करता है।
केविन बोर्रिलियन

7
ध्यान दें कि Google संग्रह को अमरूद द्वारा अधिगृहीत किया गया है, इसलिए यहां MultiMap के अमरूद संस्करण का लिंक दिया गया है: code.google.com/p/guava-lbooks/wiki/…
जोश ग्लोवर

हालांकि, मल्टीमैप पूरी तरह से सीरियल करने योग्य नहीं है, इसमें क्षणिक सदस्य हैं जो बेकार के उदाहरण को प्रस्तुत करते हैं
dschulten

@dschulten खैर, मल्टीमैप एक इंटरफेस है और आप निर्दिष्ट नहीं कर रहे हैं कि आपके लिए कौन सा कार्यान्वयन है। com.google.common.collect.HashMultimapके पास readObject/ writeObjectविधियाँ हैं, जैसा कि ArrayListMultimap और Immutable {List, Set} Multimap करते हैं। मैं एक बेकार deserialized उदाहरण एक बग रिपोर्टिंग के बारे में विचार करेगा।
एन डी।

1
Apache Collection 4.0 जेनरिक commons.apache.org/proper/commons-collections/javadocs/… का समर्थन करता है
kervin

35

हमें Google संग्रह बाहरी लाइब्रेरी पर निर्भर होने की आवश्यकता नहीं है। आप बस निम्नलिखित मानचित्र को लागू कर सकते हैं:

Map<String, ArrayList<String>> hashMap = new HashMap<String, ArrayList>();

public static void main(String... arg) {
   // Add data with duplicate keys
   addValues("A", "a1");
   addValues("A", "a2");
   addValues("B", "b");
   // View data.
   Iterator it = hashMap.keySet().iterator();
   ArrayList tempList = null;

   while (it.hasNext()) {
      String key = it.next().toString();             
      tempList = hashMap.get(key);
      if (tempList != null) {
         for (String value: tempList) {
            System.out.println("Key : "+key+ " , Value : "+value);
         }
      }
   }
}

private void addValues(String key, String value) {
   ArrayList tempList = null;
   if (hashMap.containsKey(key)) {
      tempList = hashMap.get(key);
      if(tempList == null)
         tempList = new ArrayList();
      tempList.add(value);  
   } else {
      tempList = new ArrayList();
      tempList.add(value);               
   }
   hashMap.put(key,tempList);
}

कृपया कोड को ठीक करना सुनिश्चित करें।


14
आपको निश्चित रूप से अमरूद के मल्टीमैप पर भरोसा करने की आवश्यकता नहीं है। यह आपके जीवन को आसान बनाता है, क्योंकि आपको उन्हें फिर से लागू नहीं करना है, उनका परीक्षण करना है, आदि
PhiLho

यह सभी जोड़ों पर निर्बाध पुनरावृत्ति की अनुमति नहीं देता है। कमियां जरूर हैं। मैं अपने समाधान के बारे में सुझाव देने वाला था जिसमें एक अतिरिक्त कक्षा की भी आवश्यकता थी, फिर देखा @ Mnementh का उत्तर बस यही है।
मार्क जेरोनिमस

2
बुनियादी कोड लिखना हमेशा चतुर नहीं होता है। Google के पास बेहतर परीक्षण होने की संभावना है
भावनाएं

26
Multimap<Integer, String> multimap = ArrayListMultimap.create();

multimap.put(1, "A");
multimap.put(1, "B");
multimap.put(1, "C");
multimap.put(1, "A");

multimap.put(2, "A");
multimap.put(2, "B");
multimap.put(2, "C");

multimap.put(3, "A");

System.out.println(multimap.get(1));
System.out.println(multimap.get(2));       
System.out.println(multimap.get(3));

आउटपुट है:

[A,B,C,A]
[A,B,C]
[A]

नोट: हमें लाइब्रेरी फ़ाइलों को आयात करने की आवश्यकता है।

http://www.java2s.com/Code/Jar/g/Downloadgooglecollectionsjar.htm

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

या https://commons.apache.org/proper/commons-collections/download_collections.cgi

import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;

2
अच्छा सुझाव है, क्योंकि मैं अपनी परियोजना में स्प्रिंग का उपयोग कर रहा हूं, मैंने डॉल्स http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/
html

18

आप नियमित रूप से HashMap में मूल्य के लिए मानों की एक सरणी पारित कर सकते हैं, इस प्रकार डुप्लिकेट कुंजियों का अनुकरण कर सकते हैं, और यह आप पर निर्भर करेगा कि आप किस डेटा का उपयोग करें।

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


धन्यवाद! TreeMap<String, ArrayList<MyClass>>मेरी डुप्लिकेट कुंजी को हल करने का उपयोग करना ।
जो

10

यदि आप मुख्य-मूल्य-जोड़े की सूची के बारे में पुनरावृति चाहते हैं (जैसा कि आपने टिप्पणी में लिखा है), तो एक सूची या एक सरणी बेहतर होनी चाहिए। पहले अपनी कुंजियों और मूल्यों को मिलाएं:

public class Pair
{
   public Class1 key;
   public Class2 value;

   public Pair(Class1 key, Class2 value)
   {
      this.key = key;
      this.value = value;
   }

}

Class1 और Class2 को उन प्रकारों से बदलें, जिन्हें आप कुंजियों और मूल्यों के लिए उपयोग करना चाहते हैं।

अब आप उन्हें एक सरणी या एक सूची में डाल सकते हैं और उन पर पुनरावृति कर सकते हैं:

Pair[] pairs = new Pair[10];
...
for (Pair pair : pairs)
{
   ...
}

मैं ऐड () या पुट () कैसे लागू करूंगा। मैं आयामों की हार्डकोर संख्या नहीं चाहता।
अमित कुमार गुप्ता

2
इस मामले में एक सूची का उपयोग करें। दूसरा नमूना सूची में परिवर्तन <जोड़ी> जोड़े = नई सूची <जोड़ी> (); फॉर-लूप एक समान रहता है। आप इस कमांड के साथ एक जोड़ी जोड़ सकते हैं: जोड़े.डेड (जोड़ी);
ममेन्थ

यह शायद ईमानदार होने का सबसे अच्छा जवाब है।
पॉलबगड

6

इस समस्या को मैप प्रविष्टि की सूची के साथ हल किया जा सकता है List<Map.Entry<K,V>>। हमें न तो बाहरी पुस्तकालयों और न ही मानचित्र के नए कार्यान्वयन का उपयोग करने की आवश्यकता है। एक मानचित्र प्रविष्टि इस तरह बनाई जा सकती है: Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);



3

मेरी गलतियों से सीखें ... कृपया इसे स्वयं लागू न करें। अमरूद मल्टीमप जाने का रास्ता है।

मल्टीमैप में आवश्यक आम वृद्धि डुप्लिकेट की-वैल्यू पेयर को अस्वीकृत करने के लिए है।

अपने कार्यान्वयन में इसे लागू करना / बदलना कष्टप्रद हो सकता है।

अमरूद के रूप में इसके रूप में सरल:

HashMultimap<String, Integer> no_dupe_key_plus_val = HashMultimap.create();

ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();

2

मेरे पास इस मुद्दे का थोड़ा अलग संस्करण था: एक ही कुंजी के साथ दो अलग-अलग मूल्यों को जोड़ना आवश्यक था। बस इसे यहाँ पोस्ट करने पर अगर यह दूसरों की मदद करता है, तो मैंने मूल्य के रूप में एक HashMap पेश किया है:

/* @param frameTypeHash: Key -> Integer (frameID), Value -> HashMap (innerMap)
   @param innerMap: Key -> String (extIP), Value -> String
   If the key exists, retrieve the stored HashMap innerMap 
   and put the constructed key, value pair
*/
  if (frameTypeHash.containsKey(frameID)){
            //Key exists, add the key/value to innerHashMap
            HashMap innerMap = (HashMap)frameTypeHash.get(frameID);
            innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);

        } else {
            HashMap<String, String> innerMap = new HashMap<String, String>();
            innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);
            // This means the key doesn't exists, adding it for the first time
            frameTypeHash.put(frameID, innerMap );
        }
}

उपरोक्त कोड में प्रत्येक पंक्ति में एक इनपुट फ़ाइल के पहले स्ट्रिंग से कुंजी फ़्रेमआईडी को पढ़ा जाता है, फ्रेम टाइपाइप के लिए मान शेष पंक्ति को विभाजित करके बनाया गया है और इसे मूल रूप से स्ट्रिंग ऑब्जेक्ट के रूप में संग्रहीत किया गया था, समय के साथ फ़ाइल में कई लाइनें होने लगीं अलग-अलग मूल्यों के साथ) एक ही फ्रेमआईडी कुंजी के साथ जुड़ा हुआ है, इसलिए फ्रेम टाइपाइप को मूल्य के रूप में अंतिम पंक्ति के साथ ओवरराइट किया गया था। मैंने स्ट्रिंग ऑब्जेक्ट को किसी अन्य हाशपॉइंट ऑब्जेक्ट के मान फ़ील्ड के रूप में बदल दिया, इससे एकल कुंजी को विभिन्न मूल्य मैपिंग को बनाए रखने में मदद मिली।


2

कोई फैंसी लिबास जरूरी नहीं। मैप्स को एक अद्वितीय कुंजी द्वारा परिभाषित किया जाता है, इसलिए उन्हें न झुकें, सूची का उपयोग करें। धाराएँ पराक्रमी हैं।

import java.util.AbstractMap.SimpleImmutableEntry;

List<SimpleImmutableEntry<String, String>> nameToLocationMap = Arrays.asList(
    new SimpleImmutableEntry<>("A", "A1"),
    new SimpleImmutableEntry<>("A", "A2"),
    new SimpleImmutableEntry<>("B", "B1"),
    new SimpleImmutableEntry<>("B", "B1"),
);

और बस। उपयोग के उदाहरण:

List<String> allBsLocations = nameToLocationMap.stream()
        .filter(x -> x.getKey().equals("B"))
        .map(x -> x.getValue())
        .collect(Collectors.toList());

nameToLocationMap.stream().forEach(x -> 
do stuff with: x.getKey()...x.getValue()...

1
class  DuplicateMap<K, V> 
{
    enum MapType
    {
        Hash,LinkedHash
    }

    int HashCode = 0;
    Map<Key<K>,V> map = null;

    DuplicateMap()
    {
        map = new HashMap<Key<K>,V>();
    }

    DuplicateMap( MapType maptype )
    {
        if ( maptype == MapType.Hash ) {
            map = new HashMap<Key<K>,V>();
        }
        else if ( maptype == MapType.LinkedHash ) {
            map = new LinkedHashMap<Key<K>,V>();
        }
        else
            map = new HashMap<Key<K>,V>();
    }

    V put( K key, V value  )
    {

        return map.put( new Key<K>( key , HashCode++ ), value );
    }

    void putAll( Map<K, V> map1 )
    {
        Map<Key<K>,V> map2 = new LinkedHashMap<Key<K>,V>();

        for ( Entry<K, V> entry : map1.entrySet() ) {
            map2.put( new Key<K>( entry.getKey() , HashCode++ ), entry.getValue());
        }
        map.putAll(map2);
    }

    Set<Entry<K, V>> entrySet()
    {
        Set<Entry<K, V>> entry = new LinkedHashSet<Map.Entry<K,V>>();
        for ( final Entry<Key<K>, V> entry1 : map.entrySet() ) {
            entry.add( new Entry<K, V>(){
                private K Key = entry1.getKey().Key();
                private V Value = entry1.getValue();

                @Override
                public K getKey() {
                    return Key;
                }

                @Override
                public V getValue() {
                    return Value;
                }

                @Override
                public V setValue(V value) {
                    return null;
                }});
        }

        return entry;
    }

    @Override
    public String toString() {
        StringBuilder builder = new  StringBuilder();
        builder.append("{");
        boolean FirstIteration = true;
        for ( Entry<K, V> entry : entrySet() ) {
            builder.append( ( (FirstIteration)? "" : "," ) + ((entry.getKey()==null) ? null :entry.getKey().toString() ) + "=" + ((entry.getValue()==null) ? null :entry.getValue().toString() )  );
            FirstIteration = false;
        }
        builder.append("}");
        return builder.toString();
    }

    class Key<K1>
    {
        K1 Key;
        int HashCode;

        public Key(K1 key, int hashCode) {
            super();
            Key = key;
            HashCode = hashCode;
        }

        public K1 Key() {
            return Key;
        }

        @Override
        public String toString() {
            return  Key.toString() ;
        }

        @Override
        public int hashCode() {

            return HashCode;
        }
    }

साभार @daspilker मैं अब केवल आपका संपादन देख रहा हूं। किसी को देखने के लिए मेरे स्निपेट को देखने के लिए योग्य है अगर इसे संपादित किया जाता है।
गैब्रियल डेविड

1
 1, Map<String, List<String>> map = new HashMap<>();

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

2, org.apache.commons.collections4.MultiMap interface
3, com.google.common.collect.Multimap interface 

जावा-नक्शा-डुप्लिकेट कुंजी


1

क्या इस तरह के एक मल्टीपर्प के बारे में?

public class MultiMap<K, V> extends HashMap<K, Set<V>> {
  private static final long serialVersionUID = 1L;
  private Map<K, Set<V>> innerMap = new HashMap<>();

  public Set<V> put(K key, V value) {
    Set<V> valuesOld = this.innerMap.get(key);
    HashSet<V> valuesNewTotal = new HashSet<>();
    if (valuesOld != null) {
      valuesNewTotal.addAll(valuesOld);
    }
    valuesNewTotal.add(value);
    this.innerMap.put(key, valuesNewTotal);
    return valuesOld;
  }

  public void putAll(K key, Set<V> values) {
    for (V value : values) {
      put(key, value);
    }
  }

  @Override
  public Set<V> put(K key, Set<V> value) {
    Set<V> valuesOld = this.innerMap.get(key);
    putAll(key, value);
    return valuesOld;
  }

  @Override
  public void putAll(Map<? extends K, ? extends Set<V>> mapOfValues) {
    for (Map.Entry<? extends K, ? extends Set<V>> valueEntry : mapOfValues.entrySet()) {
      K key = valueEntry.getKey();
      Set<V> value = valueEntry.getValue();
      putAll(key, value);
    }
  }

  @Override
  public Set<V> putIfAbsent(K key, Set<V> value) {
    Set<V> valueOld = this.innerMap.get(key);
    if (valueOld == null) {
      putAll(key, value);
    }
    return valueOld;
  }

  @Override
  public Set<V> get(Object key) {
    return this.innerMap.get(key);
  }

  @Override
  etc. etc. override all public methods size(), clear() .....

}

0

क्या आप उस संदर्भ को भी समझा सकते हैं जिसके लिए आप डुप्लिकेट कुंजियों के साथ एक नक्शा लागू करने की कोशिश कर रहे हैं? मुझे यकीन है कि एक बेहतर समाधान हो सकता है। नक्शे का उद्देश्य अच्छे कारणों के लिए अद्वितीय कुंजी रखना है। यद्यपि यदि आप वास्तव में करना चाहते थे; आप हमेशा क्लास का विस्तार कर सकते हैं एक सरल कस्टम मैप क्लास लिख सकते हैं जिसमें टकराव का शमन कार्य होता है और आपको एक ही कुंजी के साथ कई प्रविष्टियाँ रखने में सक्षम करेगा।

नोट: आपको टक्कर शमन क्रिया को लागू करना चाहिए जैसे, टकराने की चाबियाँ अद्वितीय सेट में बदल जाती हैं "हमेशा"। कुछ आसान है, ऑब्जेक्ट हैशकोड के साथ कुंजी जोड़ना या कुछ और?


1
संदर्भ यह है कि मैंने सोचा था कि चाबियाँ अद्वितीय होंगी, लेकिन यह पता चला है कि नहीं हो सकता है। मैं सब कुछ refactor चाहता हूँ क्योंकि यह अभ्यस्त अक्सर इस्तेमाल किया जाएगा।
एडेप्टर

मैं datatype की तरह एक छोटी XML फ़ाइल को हैशमैप में बदलना चाहता हूं। केवल समस्या XML फ़ाइल की संरचना तय नहीं है
अमित कुमार गुप्ता

0

बस पूरा होने के लिए, Apache Commons Collection के पास एक MultiMap भी है । निश्चित रूप से नकारात्मक पक्ष यह है कि अपाचे कॉमन्स जेनरिक का उपयोग नहीं करते हैं।


1
ध्यान दें कि उनका मल्टीपर्पस मैप को लागू करता है, लेकिन मैप के तरीकों के अनुबंधों को तोड़ देता है। यह मुझे परेशान करता है।
केविन बोर्रिलियन

0

एक बिट हैक के साथ आप डुप्लिकेट कुंजियों के साथ हैशसेट का उपयोग कर सकते हैं। चेतावनी: यह भारी हैशेट कार्यान्वयन पर निर्भर है।

class MultiKeyPair {
    Object key;
    Object value;

    public MultiKeyPair(Object key, Object value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public int hashCode() {
        return key.hashCode();
    }
}

class MultiKeyList extends MultiKeyPair {
    ArrayList<MultiKeyPair> list = new ArrayList<MultiKeyPair>();

    public MultiKeyList(Object key) {
        super(key, null);
    }

    @Override
    public boolean equals(Object obj) {
        list.add((MultiKeyPair) obj);
        return false;
    }
}

public static void main(String[] args) {
    HashSet<MultiKeyPair> set = new HashSet<MultiKeyPair>();
    set.add(new MultiKeyPair("A","a1"));
    set.add(new MultiKeyPair("A","a2"));
    set.add(new MultiKeyPair("B","b1"));
    set.add(new MultiKeyPair("A","a3"));

    MultiKeyList o = new MultiKeyList("A");
    set.contains(o);

    for (MultiKeyPair pair : o.list) {
        System.out.println(pair.value);
    }
}

0

यदि डुप्लिकेट कुंजियाँ हैं, तो एक कुंजी एक से अधिक मूल्य के अनुरूप हो सकती है। इन मानों की सूची के लिए कुंजी को मैप करना स्पष्ट समाधान है।

उदाहरण के लिए पायथन:

map = dict()
map["driver"] = list()
map["driver"].append("john")
map["driver"].append("mike")
print map["driver"]          # It shows john and mike
print map["driver"][0]       # It shows john
print map["driver"][1]       # It shows mike

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