2009-09-16 9 views
8

के रूप में दो संख्याओं का उपयोग कैसे करें मेरे पास दो संख्याएं हैं और मैं उन्हें Map में एक कुंजी के रूप में उपयोग करना चाहता हूं। वर्तमान में, मैं उनके स्ट्रिंग प्रस्तुतियों को जोड़ रहा हूं। उदाहरण के लिए, मान लीजिए कुंजी संख्या 4 और 12. मैं का उपयोग कर रहे हैं:मानचित्र संख्या

String key = 4 + "," + 12; 

नक्शा Map<String, Object> के रूप में घोषित किया गया है।

मुझे लगता है कि यह इतना बुरा है! मैं कुंजी के रूप में String के अलावा कुछ और उपयोग करना पसंद करता हूं! मैं इन चाबियाँ बनाने का सबसे तेज़ तरीका चाहता हूं।

किसके पास अच्छा विचार है?

+2

मुझे लगता है कि अल्पविराम-सीमित स्ट्रिंग एक अच्छा विचार है। मैं हर समय इस दृष्टिकोण का उपयोग करता हूं। – mob

उत्तर

16

एक ऐसी वस्तु बनाएं जिसमें दो संख्याएं हों और इसे कुंजी के रूप में उपयोग करें। उदाहरण के लिए:

class Coordinates { 

    private int x; 
    private int y; 

    public Coordinates(int x, int y) { 
    ... 
    } 

    // getters 

    // equals and hashcode using x and y 
} 

Map<Coordinates, Location> locations = new HashMap<Coordinates, Location>(); 

आप एक गणितीय दृष्टिकोण पसंद करते हैं, this StackOverflow answer देखते हैं।

+0

धन्यवाद, आपकी बहुत अच्छी विधि है, लेकिन मैं समस्या को हल करने के लिए "कक्षा" का उपयोग नहीं करना चाहता हूं। कुंजी प्राप्त करने के लिए सामान्य गणितीय तरीकों का उपयोग कैसे करें? मैं केवल पूछ रहा हूं, "सबसे तेज़" – Koerr

+0

ठीक है। मैंने आपके इच्छित उत्तर के लिए एक लिंक जोड़ा है :-) – SingleShot

+4

ठीक है - तो अब यह स्पष्ट रूप से एक होमवर्क समस्या है। यहां * सही * समाधान एक वर्ग का उपयोग करना है। उस वर्ग के हैशकोड() विधि का कार्यान्वयन जहां प्रदर्शन खेल में आता है। –

-5

आपको सही eqauls और हैशकोड विधियों को लिखने की आवश्यकता है, या कुछ बग का उत्पादन करें।

5

आप, लंबे समय से इस तरह की एक में दो पूर्णांकों स्टोर कर सकते हैं

long n = (l << 32) | (r & 0XFFFFFFFFL); 

या आप Pair<Integer, Integer> वर्ग निम्न का उपयोग कर सकते हैं,

public class Pair<L, R> { 

    private L l; 
    private R r; 

    public Pair() { 
    } 

    public Pair(L l, R r) { 
     this.l = l; 
     this.r = r; 
    } 

    public L getLeft() { 
     return l; 
    } 

    public R getRight() { 
     return r; 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (!(o instanceof Pair)) { 
      return false; 
     } 
     Pair obj = (Pair) o; 
     return l.equals(obj.l) && r.equals(obj.r); 
    } 

    @Override 
    public int hashCode() { 
     return l.hashCode()^r.hashCode(); 
    } 
} 
+2

मैं निफ्टी int -> लंबे समाधान के लिए इसे ऊपर उठाऊंगा, लेकिन मैं इसे 'जोड़ी' उत्परिवर्तनीय बनाने के लिए भी कम कर दूंगा। –

+0

आप जेनेरिक पैरामीटर के रूप में primitives का उपयोग नहीं कर सकते हैं। –

+0

ओह! सही किया। धन्यवाद! –

8

आप वस्तु समाधान के साथ जाते हैं, सुनिश्चित करें कि आपके कुंजी बनाने वस्तु अपरिवर्तनीय है।

अन्यथा, अगर कोई मान को बदलता है, न केवल यह अन्य स्पष्ट रूप से समान मानों के बराबर होगा, लेकिन मानचित्र में संग्रहीत हैशकोड अब hashCode() विधि द्वारा लौटाए गए किसी से मेल नहीं खाएगा। उस बिंदु पर आप मूल रूप से एसओएल हैं।

उदाहरण के लिए

, java.awt.Point का उपयोग कर - जो दिखता है, कागज पर, वास्तव में की तरह आप क्या चाहते हैं - निम्नलिखित:

public static void main(String[] args) { 
    Map<Point, Object> map = new HashMap<Point, Object>(); 

    Point key = new Point(1, 3); 
    Object val = new Object(); 

    map.put(key, val); 

    System.out.println(map.containsKey(key)); 
    System.out.println(map.containsKey(new Point(1, 3))); 

    // equivalent to setLeft()/setRight() in ZZCoder's solution, 
    // or setX()/setY() in SingleShot's 
    key.setLocation(2, 4); 

    System.out.println(map.containsKey(key)); 
    System.out.println(map.containsKey(new Point(2, 4))); 
    System.out.println(map.containsKey(new Point(1, 3))); 
    } 

प्रिंट:

true 
true 
false 
false 
false 
+0

+1 अपरिवर्तनीयता बिट – Zarkonnen

+1

+ 1 के लिए समान है, धन्यवाद, बीटीडब्ल्यू, "एसओएल" का क्या अर्थ है? – Koerr

+0

@Zenofo देखें http://www.urbandictionary.com/define.php?term=S.O.L। –

0

एक और दृष्टिकोण के लिए होगा नेस्टेड मानचित्र का उपयोग करें:

Map<Integer,Map<Integer,Object>> 

यहां कुंजी बनाने के लिए आपके ऊपर कोई ओवरहेड नहीं है। हालांकि आपके पास प्रविष्टियों को सही तरीके से बनाने और पुनर्प्राप्त करने के लिए अधिक ओवरहेड है और आपको जिस वस्तु को आप ढूंढ रहे हैं उसे ढूंढने के लिए हमेशा मानचित्र-एक्सेस की आवश्यकता होती है।

0

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

जब तक आप एक बेहद सीमित कंप्यूटिंग पावर पर्यावरण में नहीं चल रहे हैं, तब तक बनाने और हैशिंग स्ट्रिंग के ऊपरी हिस्से को आपकी कस्टम कक्षा को तुरंत चालू करने की तुलना में काफी बड़ा नहीं होना चाहिए।

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

1

एक व्यावहारिक जवाब इस सवाल के लिए है:

hashCode = a + b * 17; 

... जहां ए, बी और hashCode सभी ints हैं। 17 सिर्फ एक मनमाना प्रधान संख्या है। आपका हैश अद्वितीय नहीं होगा, लेकिन यह ठीक है। उस तरह की चीज का उपयोग पूरे जावा मानक पुस्तकालय में किया जाता है।

11

आपको java.awt.Dimension का उपयोग अपनी कुंजी के रूप में करना चाहिए।

आयाम कुंजी = नया आयाम (4, 12);

आयाम में एक बहुत अच्छी हैशकोड() विधि है जो सकारात्मक पूर्णांक की प्रत्येक जोड़ी के लिए एक अलग हैशकोड उत्पन्न करती है, ताकि हैशकोड (4, 12) और (12, 4) अलग हैं। तो ये तत्काल तेज़ हैं और बहुत अच्छे हैशकोड बनाते हैं।

मेरी इच्छा है कि उन्होंने कक्षा को अपरिवर्तनीय बना दिया हो, लेकिन आप आयाम पर अपना स्वयं का अपरिवर्तनीय वर्ग बना सकते हैं।

यहाँ चौड़ाई और ऊंचाई के विभिन्न मूल्यों के लिए hashCode दिखाने वाली एक तालिका है:

 0 1 2 3 4 <-- width 
    +-------------------- 
0 | 0 2 5 9 14 
1 | 1 4 8 13 
2 | 3 7 12 
3 | 6 11 
4 | 10 

^ 
| 
height 

आप 0 से 14 के क्रम में hashCodes का पालन करें, तो आप पैटर्न देखेंगे।

public int hashCode() { 
    int sum = width + height; 
    return sum * (sum + 1)/2 + width; 
} 

आप अंतिम पंक्ति के अंदर त्रिकोणीय संख्या के लिए सूत्र में पहचान सकते हैं:

यहाँ कोड है कि इस hashCode पैदा करता है। यही कारण है कि तालिका के पहले कॉलम में सभी त्रिकोणीय संख्याएं हैं।

गति के लिए, आपको कन्स्ट्रक्टर में हैशकोड की गणना करनी चाहिए। तो अपनी संपूर्ण कक्षा ऐसा दिखाई दे सकता:

public class PairHash { 
    private final int hash; 
    public PairHash(int a, int b) { 
    int sum = a+b; 
    hash = sum * (sum+1)/2 + a; 
    } 
    public int hashCode() { return hash; } 
} 
बेशक

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

public class PairHash { 
    // PAIR_LIMIT is 23170 
    // Keeping the inputs below this level prevents overflow, and guarantees 
    // the hash will be unique for each pair of positive integers. This 
    // lets you use the hashCode in the equals method. 
    public static final int PAIR_LIMIT = (int) (Math.sqrt(Integer.MAX_VALUE))/2; 
    private final int hash; 

    public PairHash(int a, int b) { 
    assert a >= 0; 
    assert b >= 0; 
    assert a < PAIR_LIMIT; 
    assert b < PAIR_LIMIT; 
    int sum = a + b; 
    hash = sum * (sum + 1)/2 + a; 
    } 

    public int hashCode() { return hash; } 

    public boolean equals(Object other) { 
    if (other instanceof PairHash){ 
     return hash == ((PairHash) other).hash; 
    } 
    return false; 
    } 
} 

हम इसे सकारात्मक मानों तक सीमित करते हैं क्योंकि नकारात्मक मान कुछ डुप्लिकेट हैंश कोड उत्पन्न करेंगे। लेकिन इस प्रतिबंध के साथ, ये सबसे तेज़ हैशकोड() और बराबर() विधियां हैं जिन्हें लिखा जा सकता है। (बेशक, आप हैशकोड को कन्स्ट्रक्टर में हैशकोड की गणना करके किसी भी अपरिवर्तनीय कक्षा में जितनी तेजी से लिख सकते हैं।)

यदि आप उन प्रतिबंधों के साथ नहीं रह सकते हैं, तो आपको केवल पैरामीटर को सहेजने की आवश्यकता है।

public class PairHash { 
    private final int a, b, hash; 
    public PairHash(int a, int b) { 
    this.a = a; 
    this.b = b; 
    int sum = a+b; 
    hash = sum * (sum+1)/2 + a; 
    } 
    public int hashCode() { return hash; } 
    public boolean equals(Object other) { 
    if (other instanceof PairHash) { 
     PairHash otherPair = (PairHash)other; 
     return a == otherPair.a && b == otherPair.b; 
    } 
    return false; 
} 

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

static int hashKeyFromPair(short a, short b) { 
    assert a >= 0; 
    assert b >= 0; 
    long sum = (long) a + (long) b; 
    return (int) (sum * (sum + 1)/2) + a; 
} 
+0

उत्सुकता के लिए, इस उत्तर में उपयोग किए गए फ़ंक्शन को [कैंटोर जोड़ी फ़ंक्शन] कहा जाता है (https://en.wikipedia.org/wiki/Pairing_function#Cantor_pairing_function)। – qxz

संबंधित मुद्दे