दो कुंजी (की-पेयर, मान) के साथ एक हैशपॉप कैसे बनाएं?


118

मेरे पास इंटेगर का 2 डी सरणी है। मैं चाहता हूं कि उन्हें हाशपाट में डाल दिया जाए। लेकिन मैं ऐरे इंडेक्स के आधार पर हाशप के तत्वों को एक्सेस करना चाहता हूं। कुछ इस तरह:

ए [२] [५] के लिए, map.get(2,5)जो उस कुंजी से जुड़े मान को लौटाता है। लेकिन मैं कुंजियों की एक जोड़ी के साथ एक हैशपॉप कैसे बनाऊं? या सामान्य रूप से, कई कुंजियाँ:Map<((key1, key2,..,keyN), Value) इस तरह से कि मैं तत्व का उपयोग कर प्राप्त कर सकता हूं (की 1, की 2, ... कीएन)।

संपादित करें: प्रश्न पोस्ट करने के 3 साल बाद, मैं इसे थोड़ा और जोड़ना चाहता हूं

मैं दूसरे रास्ते से आया NxN matrix

सूचकांकों को इंगित करें, iऔर निम्न तरीके से jएक के रूप में प्रतिनिधित्व किया जा सकता है key:

int key = i * N + j;
//map.put(key, a[i][j]); // queue.add(key); 

और सूचकांकों को keyइस तरह से वापस लिया जा सकता है :

int i = key / N;
int j = key % N;

एक सरल उपाय है एक कुंजी को अन्य हैशमैप में मैप करना।
Mihai8

1
कृपया प्रश्न में प्रश्न का उत्तर न दें। आपका संपादन दिलचस्प है, इसलिए इसे उत्तर के रूप में पोस्ट करने के लिए स्वतंत्र महसूस करें।
ओले वीवी

@ क्रोकोडेड वाह! एडिट में उत्तर के पीछे के गणित चिंतनशील हैं। बस सोच रहा था कि क्या यह किसी भी दो पूर्णांक i और j के लिए सामान्य रूप से काम करता है।
जैज

@ यदि मैं N के गुणक हैं तो क्या मैं और j पर चक्र लगाएगा?
likejudo

जवाबों:


190

कई विकल्प हैं:

2 आयाम

नक्शों का नक्शा

Map<Integer, Map<Integer, V>> map = //...
//...

map.get(2).get(5);

आवरण की मुख्य वस्तु

public class Key {

    private final int x;
    private final int y;

    public Key(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Key)) return false;
        Key key = (Key) o;
        return x == key.x && y == key.y;
    }

    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }

}

लागू करना equals()और hashCode()यहाँ महत्वपूर्ण है। तो आप बस का उपयोग करें:

Map<Key, V> map = //...

तथा:

map.get(new Key(2, 5));

Table अमरूद से

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

table.get(2, 5);

Tableनक्शे के नक्शे का उपयोग करता है है।

एन आयाम

ध्यान दें कि Keyकेवल विशेष वर्ग ही एकमात्र दृष्टिकोण है जो n- आयामों के लिए है। आप इस पर भी विचार कर सकते हैं:

Map<List<Integer>, V> map = //...

लेकिन यह प्रदर्शन के दृष्टिकोण से भयानक है, साथ ही पठनीयता और शुद्धता (सूची आकार लागू करने का कोई आसान तरीका नहीं है)।

शायद स्काला पर एक नज़र डालें जहाँ आपके पास ट्यूपल्स और caseकक्षाएं हैं (पूरी Keyकक्षा को एक-लाइनर के साथ बदलना )।


3
नमस्ते, जब हैशकोड करते समय दूसरों के दो मान होते हैं। आप 31 का उपयोग क्यों करते हैं? मैंने सोचा कि इसका 32-बिट पूर्णांक के साथ कुछ करना है, लेकिन जब मैं इसके बारे में सोचता हूं तो इसका कोई मतलब नहीं है, क्योंकि x = 1 और y = 0 अभी भी उसी हैशकोड के लिए x = 0 और y = 31 के रूप में मैप करता है
पीट

1
@pete जोशुआ बलोच, प्रभावी जावा ch 3. s 9. में, "1. कुछ निरंतर नॉनज़ेरो वैल्यू को स्टोर करें, 17, परिणाम कहे जाने वाले int variable में स्टोर करें ...", जो बेहतर टक्कर-वार का काम करता है एक प्रमुख। इन्हें भी देखें: stackoverflow.com/questions/3613102/…
fncomp

2
आवरण कुंजी वस्तु के बजाय कुंजी के Map.Entry<K, V>रूप में उपयोग क्यों नहीं किया जाता है?
रोलैंड

1
किस बारे में Map<Pair<Key1, Key2>, Value>?
जोक्विन इराचुक

1
ध्यान दें कि hashCode()एक लाइन के साथ भी लागू किया जा सकता हैObjects.hash(x,y)
xdavidliu

23

जब आप अपनी खुद की कुंजी जोड़ी बनाते हैं, तो आपको कुछ चीजों का सामना करना चाहिए।

सबसे पहले, आपको लागू करने के बारे में पता होना चाहिए hashCode()और equals()। आपको ऐसा करने की आवश्यकता होगी।

दूसरा, लागू करते समय hashCode(), सुनिश्चित करें कि आप समझते हैं कि यह कैसे काम करता है। दिए गए उपयोगकर्ता उदाहरण

public int hashCode() {
    return this.x ^ this.y;
}

वास्तव में सबसे खराब कार्यान्वयन में से एक है जो आप कर सकते हैं। कारण सरल है: आपके पास बहुत अधिक हैश है! और ऐसे hashCode()इंट्रा वैल्यूज लौटाने चाहिए जो सबसे अच्छे, अनूठे हों, यह सबसे अच्छा है। कुछ इस तरह का उपयोग करें:

public int hashCode() {
  return (X << 16) + Y;
}

यह तेज है और -2 ^ 16 और 2 ^ 16-1 (-65536 से 65535) के बीच कुंजियों के लिए अद्वितीय हैश देता है। यह लगभग किसी भी मामले में फिट बैठता है। बहुत कम ही आप इस सीमा से बाहर हैं।

तीसरा, जब लागू हो equals() यह भी जानता है कि इसका उपयोग किस लिए किया जाता है और इस बात से अवगत रहें कि आप अपनी चाबी कैसे बनाते हैं, क्योंकि वे वस्तुएं हैं। अक्सर आप अनावश्यक करते हैं यदि बयानों का कारण बनता है तो आपके पास हमेशा एक ही परिणाम होगा।

यदि आप इस तरह से चाबियाँ बनाते हैं: map.put(new Key(x,y),V);तो आप कभी भी अपनी कुंजी के संदर्भों की तुलना नहीं करेंगे। हर बार जब आप नक्शे को आरोपित करना चाहते हैं, तो आप कुछ ऐसा करेंगे map.get(new Key(x,y));। इसलिए आपके equals()कथन की आवश्यकता नहीं है if (this == obj)। यह कभी नहीं होगा ।

इसके बजाय if (getClass() != obj.getClass())अपने equals()बेहतर उपयोग में if (!(obj instanceof this))। यह उपवर्गों के लिए भी मान्य होगा।

तो केवल एक चीज जिसकी आपको तुलना करने की आवश्यकता है वह वास्तव में एक्स और वाई है। इसलिए equals()इस मामले में सबसे अच्छा कार्यान्वयन होगा:

public boolean equals (final Object O) {
  if (!(O instanceof Key)) return false;
  if (((Key) O).X != X) return false;
  if (((Key) O).Y != Y) return false;
  return true;
}

तो अंत में आपका प्रमुख वर्ग इस प्रकार है:

public class Key {

  public final int X;
  public final int Y;

  public Key(final int X, final int Y) {
    this.X = X;
    this.Y = Y;
  }

  public boolean equals (final Object O) {
    if (!(O instanceof Key)) return false;
    if (((Key) O).X != X) return false;
    if (((Key) O).Y != Y) return false;
    return true;
  }

  public int hashCode() {
    return (X << 16) + Y;
  }

}

आप अपने आयाम सूचकांकों Xऔर Yएक सार्वजनिक पहुंच स्तर दे सकते हैं , इस तथ्य के कारण कि वे अंतिम हैं और संवेदनशील जानकारी शामिल नहीं है। मुझे कोई 100% यकीन नहीं है कि क्या किसी भी मामले privateमें एक्सेस स्तर सही ढंग से काम करता है जब कोई कास्टिंग करता ObjectहैKey

यदि आप फाइनल के बारे में आश्चर्य करते हैं, तो मैं किसी भी चीज को अंतिम घोषित करता हूं कि कौन सा मूल्य अस्थिरता पर सेट है और कभी नहीं बदलता है - और इसलिए एक वस्तु स्थिर है।


7

आपके पास एकाधिक कुंजी के साथ हैश मैप नहीं हो सकता है, लेकिन आपके पास एक ऑब्जेक्ट हो सकता है जो कुंजी के रूप में कई पैरामीटर लेता है।

इंडेक्स नामक एक ऑब्जेक्ट बनाएं जो x और y मान लेता है।

public class Index {

    private int x;
    private int y;

    public Index(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public int hashCode() {
        return this.x ^ this.y;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Index other = (Index) obj;
        if (x != other.x)
            return false;
        if (y != other.y)
            return false;
        return true;
    }
}

फिर HashMap<Index, Value>अपना रिजल्ट पाना है। :)


4
आप ओवरराइड करने के लिए की जरूरत है hashCodeऔर equals
टॉम हॉल्टिन -

4
हैशकोड कार्यान्वयन (2,1) और (1,2) के बीच अंतर नहीं किया गया
user1947415

1
वह टक्कर है। हैशकोड को हर अलग ऑब्जेक्ट के लिए अलग-अलग मूल्य की गारंटी देने की आवश्यकता नहीं है। @ user1947415
अजाक

6

सामान्य-संग्रह MultiKeyMap में कार्यान्वित किया गया


@Wilson मैंने अभी लिंक को ठीक किया है, सहकर्मी समीक्षा की प्रतीक्षा कर रहा है
कंप्यूटिंग

@computingfreak लगता है जैसे एक अनुकूल दृश्य के माध्यम से आया था। हुर्रे! NB यह सबसे अच्छा जवाब IMHO है। जब तक आप कुछ अधिक उपयोगी (हमेशा की तरह) लेकिन अंततः कार्यक्षमता के सांसारिक टुकड़े पर विशेषज्ञ अपाचे इंजीनियरों के साथ प्रतिस्पर्धा करने वाले घंटे खर्च करते हैं।
माइक कृंतक

4

दो संभावनाएँ। या तो एक संयुक्त कुंजी का उपयोग करें:

class MyKey {
    int firstIndex;
    int secondIndex;
    // important: override hashCode() and equals()
}

या मानचित्र का नक्शा:

Map<Integer, Map<Integer, Integer>> myMap;

2
यदि आप प्रदर्शन या मेमोरी के उपयोग की परवाह नहीं करते हैं, तो केवल नक्शे के नक्शे का उपयोग करें (यानी, नक्शा छोटा है), या एक ही पहले सूचकांक के साथ कई चाबियाँ हैं - चूंकि इस समाधान का अर्थ है, किसी HashMap वस्तु के ओवरहेड का भुगतान करना हर एक अद्वितीय पहला सूचकांक।
BeeOnRope

1
इस उत्तर को बेहतर बनाने के लिए यहां ओवरराइडिंग hashCodeऔर equalsतरीकों के बारे में जानकारी दी गई है ।
Pshemo

2

Pairकुंजी के रूप में उपयोग करें HashMap। JDK की कोई जोड़ी नहीं है, लेकिन आप या तो http://commons.apache.org/lang जैसी किसी 3 पार्टी के लाइब्रेर का उपयोग कर सकते हैं या अपनी खुद की एक जोड़ी टाइप कर सकते हैं।


1

एक मूल्य वर्ग बनाएं जो आपकी यौगिक कुंजी का प्रतिनिधित्व करेगा, जैसे:

class Index2D {
  int first, second;

  // overrides equals and hashCode properly here
}

ओवरराइड equals()और hashCode()सही तरीके से देखभाल करना । यदि यह बहुत काम की तरह लगता है, तो आप कुछ तैयार किए गए सामान्य कंटेनरों पर विचार कर सकते हैं, जैसे कि Pairदूसरों के बीच अपाचे कॉमन्स द्वारा प्रदान किया गया है।

अन्य विचारों के साथ यहां भी कई समान प्रश्न हैं, जैसे कि अमरूद की मेज का उपयोग करना , हालांकि चाबियों के विभिन्न प्रकार हैं, जो आपके मामले में ओवरकिल (स्मृति उपयोग और जटिलता) में हो सकती हैं क्योंकि मैं समझता हूं कि आपकी चाबियाँ दोनों पूर्णांक हैं।


1

यदि वे दो पूर्णांक हैं, तो आप एक त्वरित और गंदी चाल की कोशिश कर सकते हैं: Map<String, ?>कुंजी का उपयोग करके i+"#"+j

यदि कुंजी प्रयास i+"#"+jके समान है ।j+"#"+imin(i,j)+"#"+max(i,j)


2
वास्तव में बुरा विचार। सबसे पहले, यह सिर्फ बुरा है। दूसरे, इस तकनीक को अन्य प्रकारों के लिए कॉपी किया जाएगा जहां अलग-अलग कुंजी Stringउल्लिखित परिणाम के साथ मैप की जा सकती हैं ।
टॉम हॉकिन -

यह मुझे लगता है कि i#j = j#iजब चाल i == jका उपयोग min/maxनहीं करेंगे।
मैथ्यू

1
@ मैथ्यू क्या अंतर है 5#5और 5#5चारों ओर अदला-बदली?
1

@ श्रेय कोई नहीं। यही मैं इशारा कर रहा था। यह वास्तव में आपके पास आपकी चाबियों के ज्ञान पर निर्भर करता है।
मैथ्यू

@ मैथ्यू अहा मैं देख रहा हूं कि आपका क्या मतलब है। मुझे लगता है कि @arutaku का मतलब क्या था जब आप 5#3उसी तरह हैश करना चाहते हैं 3#5, तो आप 3#5इस क्रम में लागू करने के लिए न्यूनतम / अधिकतम का उपयोग करते हैं ।
enrey

1

आप इसके लिए अमरूद की मेज का उपयोग भी कर सकते हैं ।

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

//create a table
  Table<String, String, String> employeeTable = HashBasedTable.create();

  //initialize the table with employee details
  employeeTable.put("IBM", "101","Mahesh");
  employeeTable.put("IBM", "102","Ramesh");
  employeeTable.put("IBM", "103","Suresh");

  employeeTable.put("Microsoft", "111","Sohan");
  employeeTable.put("Microsoft", "112","Mohan");
  employeeTable.put("Microsoft", "113","Rohan");

  employeeTable.put("TCS", "121","Ram");
  employeeTable.put("TCS", "122","Shyam");
  employeeTable.put("TCS", "123","Sunil");

  //get Map corresponding to IBM
  Map<String,String> ibmEmployees =  employeeTable.row("IBM");

1

आप अपनी मुख्य वस्तु कुछ इस तरह से बना सकते हैं:

सार्वजनिक वर्ग MapKey {

public  Object key1;
public Object key2;

public Object getKey1() {
    return key1;
}

public void setKey1(Object key1) {
    this.key1 = key1;
}

public Object getKey2() {
    return key2;
}

public void setKey2(Object key2) {
    this.key2 = key2;
}

public boolean equals(Object keyObject){

    if(keyObject==null)
        return false;

    if (keyObject.getClass()!= MapKey.class)
        return false;

    MapKey key = (MapKey)keyObject;

    if(key.key1!=null && this.key1==null)
        return false;

    if(key.key2 !=null && this.key2==null)
        return false;

    if(this.key1==null && key.key1 !=null)
        return false;

    if(this.key2==null && key.key2 !=null)
        return false;

    if(this.key1==null && key.key1==null && this.key2 !=null && key.key2 !=null)
        return this.key2.equals(key.key2);

    if(this.key2==null && key.key2==null && this.key1 !=null && key.key1 !=null)
        return this.key1.equals(key.key1);

    return (this.key1.equals(key.key1) && this.key2.equals(key2));
}

public int hashCode(){
    int key1HashCode=key1.hashCode();
    int key2HashCode=key2.hashCode();
    return key1HashCode >> 3 + key2HashCode << 5;
}

}

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

नोट : आपका की 1 और की 2 अपरिवर्तनीय होना चाहिए। तभी आप एक स्थिर कुंजी ऑब्जेक्ट का निर्माण कर पाएंगे।


1

हम एक से अधिक कुंजी या मान पास करने के लिए एक वर्ग बना सकते हैं और इस वर्ग की वस्तु को मानचित्र में एक पैरामीटर के रूप में उपयोग किया जा सकता है।

import java.io.BufferedReader; 
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

 public class key1 {
    String b;
    String a;
    key1(String a,String b)
    {
        this.a=a;
        this.b=b;
    }
  }

public class read2 {

private static final String FILENAME = "E:/studies/JAVA/ReadFile_Project/nn.txt";

public static void main(String[] args) {

    BufferedReader br = null;
    FileReader fr = null;
    Map<key1,String> map=new HashMap<key1,String>();
    try {

        fr = new FileReader(FILENAME);
        br = new BufferedReader(fr);

        String sCurrentLine;

        br = new BufferedReader(new FileReader(FILENAME));

        while ((sCurrentLine = br.readLine()) != null) {
            String[] s1 = sCurrentLine.split(",");
            key1 k1 = new key1(s1[0],s1[2]);
            map.put(k1,s1[2]);
        }
        for(Map.Entry<key1,String> m:map.entrySet()){  
            key1 key = m.getKey();
            String s3 = m.getValue();
               System.out.println(key.a+","+key.b+" : "+s3);  
              }  
  //            }   
        } catch (IOException e) {

        e.printStackTrace();

    } finally {

        try {

            if (br != null)
                br.close();

            if (fr != null)
                fr.close();

        } catch (IOException ex) {

            ex.printStackTrace();

        }

    }

    }

 }

0

आप इसे नीचे दिए गए लिंक से डाउनलोड कर सकते हैं: https://github.com/VVS279/DoubleKeyHashMap/blob/master/src/com/virtualMark/doubleKeyHashMap/DoubleKeyHashMap.java

https://github.com/VVS279/DoubleKeyHashMap

आप दोहरी कुंजी का उपयोग कर सकते हैं: मान हैशमैप,

   DoubleKeyHashMap<Integer, Integer, String> doubleKeyHashMap1 = new 
   DoubleKeyHashMap<Integer, Integer, String>();

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