2012-07-28 12 views
22

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

मैं बस दो तारों को जोड़ सकता हूं, लेकिन मुझे यकीन है कि ऐसा करने का एक बेहतर तरीका है।

उत्तर

37

आप दो स्ट्रिंग से युक्त एक कस्टम वस्तु हो सकता था।

समानता दोनों तारों पर मैच हो सकता है और hashCode श्रेणीबद्ध सदस्यों की hashCode हो सकता है (यह बहस का मुद्दा है):

class StringKey { 
    private String str1; 
    private String str2; 

    @Override 
    public boolean equals(Object obj) { 
     if(obj != null && obj instanceof StringKey) { 
      StringKey s = (StringKey)obj; 
      return str1.equals(s.str1) && str2.equals(s.str2); 
     } 
     return false; 
    } 

    @Override 
    public int hashCode() { 
     return (str1 + str2).hashCode(); 
    } 
} 
+1

क्या एबीसी, डी और एबी के लिए हैशकोड के कारण कोई समस्या है, सीडी समान है? या बराबर अलग संकल्प है कि? –

+1

@smackfu: यह निर्भर करता है। यह केवल एक समस्या होगी यदि आपके पास तारों के ऐसे कई जोड़े हैं, क्योंकि वे तालिका में एक ही स्लॉट के लिए हैश और लुकअप कम कुशल बनाते हैं। – Tudor

+0

@ ट्यूडर क्या आप किसी भी लाभ के बारे में सोच सकते हैं कि इस समाधान में एजसेज़ द्वारा प्रस्तुत समाधान पर है जो मूल रूप से केवल दो तारों को एक टिल्ड चरित्र से अलग करता है? – Zak

7

क्यों नहीं (कहें) Pair ऑब्जेक्ट, जिसमें सदस्यों के रूप में दो स्ट्रिंग शामिल हैं, और फिर इसे कुंजी के रूप में उपयोग करें?

उदा

public class Pair { 
    private final String str1; 
    private final String str2; 

    // this object should be immutable to reliably perform subsequent lookups 
} 

equals() के बारे में और hashCode() मत भूलना। अपरिवर्तनीयता आवश्यकताओं पर पृष्ठभूमि सहित हैशमैप्स और कुंजियों पर अधिक के लिए this blog entry देखें। यदि आपकी कुंजी अपरिवर्तनीय नहीं है, तो आप इसके घटकों को बदल सकते हैं और बाद वाला लुकअप इसे ढूंढने में असफल हो जाएगा (यही कारण है कि String जैसी अपरिवर्तनीय वस्तुएं कुंजी के लिए अच्छे उम्मीदवार हैं)

आप सही हैं कि concatenation isn आदर्श नहीं है। कुछ परिस्थितियों के लिए यह काम करेगा, लेकिन यह अक्सर एक अविश्वसनीय और नाजुक समाधान होता है (उदाहरण के लिए एबी/सीए/बीसी से एक अलग कुंजी है?)। आप समानता परीक्षण और इस तरह के दो वस्तुओं के लिए हैश कोड निर्धारण करने की आवश्यकता

class StringKey { 
    private String str1; 
    private String str2; 
} 

समस्या है,:

+0

यदि हमें कई प्रविष्टियां हैं (~ 77,500) तो क्या हम खुद को हैश टकराव के साथ पा सकते हैं? – lolo

4

मैं एक ऐसी ही मामला है। मैं बस एक tilde (~) से अलग दो तारों को जोड़ता हूं।

तो जब ग्राहक के नक्शे से वस्तु प्राप्त करने के लिए सेवा फ़ंक्शन को कॉल करने, यह इस तरह दिखता है:

MyObject getMyObject(String key1, String key2) { 
    String cacheKey = key1 + "~" + key2; 
    return map.get(cachekey); 
} 

यह आसान है, लेकिन यह काम करता है।

1
public static String fakeMapKey(final String... arrayKey) { 
    String[] keys = arrayKey; 

    if (keys == null || keys.length == 0) 
     return null; 

    if (keys.length == 1) 
     return keys[0]; 

    String key = ""; 
    for (int i = 0; i < keys.length; i++) 
     key += "{" + i + "}" + (i == keys.length - 1 ? "" : "{" + keys.length + "}"); 

    keys = Arrays.copyOf(keys, keys.length + 1); 

    keys[keys.length - 1] = FAKE_KEY_SEPARATOR; 

    return MessageFormat.format(key, (Object[]) keys);} 
public static string FAKE_KEY_SEPARATOR = "~"; 

INPUT: fakeMapKey("keyPart1","keyPart2","keyPart3");
OUTPUT: keyPart1~keyPart2~keyPart3
9
public int hashCode() { 
    return (str1 + str2).hashCode(); 
} 

यह एक भयानक तरीका hashCode उत्पन्न करने के लिए हो रहा है: एक नया स्ट्रिंग उदाहरण बनाना हर बार हैश कोड गणना की जाती है भयानक है! (यहां तक ​​कि स्ट्रिंग उदाहरण एक बार पैदा करने और परिणाम कैशिंग गरीब प्रथा है।)

यहाँ सुझावों की एक बहुत कुछ कर रहे हैं: तार की एक जोड़ी के लिए

How do I calculate a good hash code for a list of strings?

public int hashCode() { 
    final int prime = 31; 
    int result = 1; 
    for (String s : strings) { 
     result = result * prime + s.hashCode(); 
    } 
    return result; 
} 

, कि हो जाता है:

return string1.hashCode() * 31 + string2.hashCode(); 

यह एक बहुत ही बुनियादी कार्यान्वयन है। बेहतर ट्यूनेड रणनीतियों का सुझाव देने के लिए लिंक के माध्यम से बहुत सारी सलाह।

+0

"हैश कोड की गणना के हर बार एक नया स्ट्रिंग उदाहरण" - हाहाहा, अच्छी तरह से देखा गया! –

2

मुझे लगता है कि कई लोग नेस्टेड मानचित्र का उपयोग करते हैं। यही है, Key1 -> Key2 -> Value मैप करने के लिए (मैं (Key1 x Key2) -> Value मैपिंग के लिए कंप्यूटर विज्ञान/उर्फ ​​हैकेल कर्लिंग नोटेशन का उपयोग करता हूं जिसमें दो तर्क हैं और एक मूल्य उत्पन्न करते हैं), आप पहली बार पहली कुंजी की आपूर्ति करते हैं - यह आपको (partial) mapKey2 -> Value देता है, जिसे आप प्रकट करते हैं अगला कदम।

उदाहरण के लिए,

Map<File, Map<Integer, String>> table = new HashMap(); // maps (File, Int) -> Distance 

add(k1, k2, value) { 
    table2 = table1.get(k1); 
    if (table2 == null) table2 = table1.add(k1, new HashMap()) 
    table2.add(k2, value) 
} 

get(k1, k2) { 
    table2 = table1.get(k1); 
    return table2.get(k2) 
} 

मुझे यकीन है कि यह अच्छा है या नहीं सादे समग्र कुंजी निर्माण की तुलना में है नहीं कर रहा हूँ। आप उस पर टिप्पणी कर सकते हैं।

2

स्पैगुएटी/कैक्टस स्टैक के बारे में पढ़ना मैं एक ऐसे संस्करण के साथ आया जो इस उद्देश्य के लिए सेवा कर सकता है, जिसमें किसी भी क्रम में अपनी चाबियों को मैप करने की संभावना शामिल है ताकि map.lookup ("a", "b") और मानचित्र .lookup ("बी", "ए") एक ही तत्व देता है। यह किसी भी कुंजी के साथ काम करता है न केवल दो।

मैं dataflow प्रोग्रामिंग के साथ प्रयोग करने के लिए एक ढेर के रूप में उपयोग लेकिन यहाँ एक त्वरित और गंदे संस्करण है जो (यह सुधार किया जाना चाहिए एक बहु कुंजी नक्शे के रूप में काम करता है: के डुप्लिकेट आवृत्तियों को देख से बचने के लिए इस्तेमाल किया जाना चाहिए सेट सरणियों के बजाय एक प्रमुख)

public class MultiKeyMap <K,E> { 
    class Mapping { 
     E element; 
     int numKeys; 
     public Mapping(E element,int numKeys){ 
      this.element = element; 
      this.numKeys = numKeys; 
     } 
    } 
    class KeySlot{ 
     Mapping parent; 
     public KeySlot(Mapping mapping) { 
      parent = mapping; 
     } 
    } 
    class KeySlotList extends LinkedList<KeySlot>{} 
    class MultiMap extends HashMap<K,KeySlotList>{} 
    class MappingTrackMap extends HashMap<Mapping,Integer>{} 

    MultiMap map = new MultiMap(); 

    public void put(E element, K ...keys){ 
     Mapping mapping = new Mapping(element,keys.length); 
     for(int i=0;i<keys.length;i++){ 
      KeySlot k = new KeySlot(mapping); 
      KeySlotList l = map.get(keys[i]); 
      if(l==null){ 
       l = new KeySlotList(); 
       map.put(keys[i], l); 
      } 
      l.add(k); 
     } 
    } 
    public E lookup(K ...keys){ 
     MappingTrackMap tmp = new MappingTrackMap(); 
     for(K key:keys){ 
      KeySlotList l = map.get(key); 
      if(l==null)return null; 
      for(KeySlot keySlot:l){ 
       Mapping parent = keySlot.parent; 
       Integer count = tmp.get(parent); 
       if(parent.numKeys!=keys.length)continue; 
       if(count == null){ 
        count = parent.numKeys-1; 
       }else{ 
        count--; 
       } 
       if(count == 0){ 
        return parent.element; 
       }else{ 
        tmp.put(parent, count); 
       }    
      } 
     } 
     return null; 
    } 
    public static void main(String[] args) { 
     MultiKeyMap<String,String> m = new MultiKeyMap<String,String>(); 
     m.put("brazil", "yellow", "green"); 
     m.put("canada", "red", "white"); 
     m.put("USA", "red" ,"white" ,"blue"); 
     m.put("argentina", "white","blue"); 

     System.out.println(m.lookup("red","white")); // canada 
     System.out.println(m.lookup("white","red")); // canada 
     System.out.println(m.lookup("white","red","blue")); // USA 
    } 
} 
2

आप पहिया बदलने की जरूरत नहीं है। अपनी आवश्यकता के लिए Table<R,C,V> इंटरफेस के Guava के HashBasedTable<R,C,V> कार्यान्वयन का उपयोग करें। यहां एक उदाहरण है

Table<String, String, Integer> table = HashBasedTable.create(); 

table.put("key-1", "lock-1", 50); 
table.put("lock-1", "key-1", 100); 

System.out.println(table.get("key-1", "lock-1")); //prints 50 
System.out.println(table.get("lock-1", "key-1")); //prints 100 

table.put("key-1", "lock-1", 150); //replaces 50 with 150 

हैप्पी कोडिंग!