দুটি কী (কী-পেয়ার, মান) দিয়ে একটি হ্যাশম্যাপ তৈরি করবেন?


118

আমার পূর্ণসংখ্যার 2D অ্যারে রয়েছে। আমি তাদের হ্যাশম্যাপে রাখতে চাই। তবে অ্যারে ইনডেক্সের ভিত্তিতে আমি হ্যাশম্যাপ থেকে উপাদানগুলি অ্যাক্সেস করতে চাই। কিছুটা এইরকম:

A [2] [5] এর জন্য, map.get(2,5)যা সেই কীটির সাথে যুক্ত একটি মান প্রদান করে। তবে কীভাবে এক জোড়া কী দিয়ে হ্যাশম্যাপ তৈরি করব? বা সাধারণভাবে, একাধিক কী: Map<((key1, key2,..,keyN), Value)এমনভাবে আমি get (কী 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;

একটি সহজ সমাধান হ'ল অন্য হ্যাশম্যাপে একটি কী ম্যাপিং।
মিহাই 8

1
দয়া করে প্রশ্নের উত্তর দিন না। আপনার সম্পাদনা আকর্ষণীয়, তাই এটি একটি উত্তর হিসাবে পোস্ট নির্দ্বিধায়।
ওলে ভিভি

@ ক্রোকোড বাহ! সম্পাদনায় উত্তরের পিছনে গণিতগুলি স্কিনটিলেটিং la আমি এবং জে কোনও দুটি পূর্ণসংখ্যার জন্য এটি সাধারণভাবে কাজ করে কিনা তা কেবল ভাবছি।
likejudo

@ ক্রোকোড আমি এবং জে সাইকেল চালিয়ে যাব যদি তারা এন এর গুণক হয়?
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
হাই, হ্যাশকোড করার সময় অন্যের দুটিই মান রয়েছে x আপনি 31 ব্যবহার করেন কেন? আমি ভেবেছিলাম এটা 32 বিট পূর্ণসংখ্যা দিয়ে কি কিছু আছে, কিন্তু যখন আমি এটা আমার মনে হয় এটা জানার জন্য না, কারণ এক্স = 1 এবং y = 0 এখনো এক্স = 0 হিসাবে একই হ্যাশকোড করার মানচিত্র এবং y = 31
পিট

1
কার্যকর জেভা সিএইচ s. এস এর 9. পেইজ জোশুয়া ব্লচ সুপারিশ করেছেন, "১. কিছু ধ্রুবক ননজারো মান সংরক্ষণ করুন, বলুন, ১,, ফল হিসাবে পরিচিত একটি পরিবর্তনশীল ...", এটি যদি আরও ভাল সংঘর্ষের ভিত্তিতে কাজ করে তবে একটি প্রধান আরও দেখুন: 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))। এটি এমনকি সাবক্লাসের জন্য বৈধ হবে।

সুতরাং আপনাকে কেবলমাত্র তুলনা করার দরকারটি হ'ল আসলে এক্স এবং ওয়াই So তাই 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

আপনার একাধিক কী সহ একটি হ্যাশ মানচিত্র থাকতে পারে না, তবে আপনার কাছে এমন কোনও বস্তু থাকতে পারে যা কী হিসাবে একাধিক পরামিতি নেয়।

সূচক নামে একটি অবজেক্ট তৈরি করুন যা একটি এক্স এবং ওয়াইয়ের মান নেয়।

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)
ব্যবহারকারী 1947415

1
এটাই সংঘর্ষ। হ্যাশকোডকে প্রতিটি পৃথক বস্তুর জন্য পৃথক মানের গ্যারান্টি দেওয়ার দরকার নেই। @ ব্যবহারকারী1947415
আজাক

6

@ উইলসন আমি এখনই লিঙ্কটি ঠিক করেছি, পিয়ারের পর্যালোচনার জন্য অপেক্ষা করছি
কম্পিউটিংফ্র্যাক করুন

@ কমপুটিংফ্রাইক দেখে মনে হচ্ছে কোনও অনুকূল ভিউ এসেছে। Hurray থেকে! এনবি এটি সেরা উত্তর আইএমএইচও। বিশেষজ্ঞ অ্যাপাচি ইঞ্জিনিয়ারদের সাথে প্রতিযোগিতা করার সময় অবধি কল্যাণকর না হলে কিছু কার্যকর (কখনও হিসাবে) তবে শেষ পর্যন্ত কার্যকারিতার টুকরো টুকরো টুকরো।
মাইক রডেন্ট

4

দুটি সম্ভাবনা। হয় সম্মিলিত কী ব্যবহার করুন:

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

অথবা মানচিত্রের একটি মানচিত্র:

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

2
আপনি যদি এখানে কর্মক্ষমতা বা মেমরির ব্যবহারের বিষয়ে চিন্তা না করেন তবে কেবলমাত্র মানচিত্রের মানচিত্রটি ব্যবহার করুন (যেমন, মানচিত্রটি ছোট), বা একই প্রথম সূচকের সাথে অনেকগুলি কী রয়েছে - যেহেতু এই সমাধানটির জন্য হ্যাশম্যাপ অবজেক্টের ওভারহেড প্রদান করা হবে প্রতিটি একক অনন্য প্রথম সূচক।
BeeOnRope

1
এই উত্তরটির উন্নতি করতে এখানে ওভাররাইডিং hashCodeএবং equalsপদ্ধতিগুলি সম্পর্কে তথ্য is
Pshemo

2

একটি ব্যবহার করুন Pairজন্য কী হিসেবে HashMap। জেডিকে কোনও জুড়ি নেই তবে আপনি হয় তৃতীয় পক্ষের লাইব্রেরি যেমন ব্যবহার করতে পারেন http://commons.apache.org/lang বা নিজের একটি জুড়ি টাইপ লিখতে পারেন।


1

এমন একটি মান শ্রেণি তৈরি করুন যা আপনার যৌগিক কী উপস্থাপন করবে, যেমন:

class Index2D {
  int first, second;

  // overrides equals and hashCode properly here
}

ওভাররাইড equals()এবং hashCode()সঠিকভাবে যত্ন নেওয়া । যদি এটি বেশ কাজের মতো মনে হয় তবে আপনি কিছু তৈরি জেনেরিক পাত্রে যেমন বিবেচনা করতে পারেনPair অন্যদের মধ্যে অ্যাপাচি কমন্স সরবরাহ করে।

এছাড়াও আছে অনেক অনুরূপ প্রশ্ন এখানে, এই ধরনের পেয়ারা এর ব্যবহার অন্যান্য ধারনা সঙ্গে ছক , যদিও কী বিভিন্ন ধরনের, যা Overkill হতে পারে আপনার ক্ষেত্রে (মেমরি ব্যবহার ও জটিলতা নেই) যেহেতু আমি বুঝতে আপনার কি উভয় পূর্ণসংখ্যা করতে সক্ষম হবেন।


1

যদি সেগুলি দুটি পূর্ণসংখ্যার হয় তবে আপনি দ্রুত এবং নোংরা কৌশলটি চেষ্টা করতে পারেন: Map<String, ?>কী হিসাবে এটি ব্যবহার করে i+"#"+j

চাবিটি i+"#"+jযদি একই হয় তবে j+"#"+iচেষ্টা করুন min(i,j)+"#"+max(i,j)


2
সত্যিই খারাপ ধারণা। প্রথমত, এটি কেবল খারাপ। দ্বিতীয়ত, এই কৌশলটি অন্যান্য ধরণের জন্য অনুলিপি করা হবে যেখানে বিভিন্ন কী কী উপভোগ করতে পারে Stringila
টম হাটিন -

আমার কাছে মনে হয় যে i#j = j#iযখন কৌশলটি i == jব্যবহার করা min/maxহবে তখন তা করবে না।
ম্যাথিউউ

1
@ ম্যাথিউউ এর মধ্যে পার্থক্য কী 5#5এবং 5#5চারপাশে অদলবদল?
enrey

পছন্দ করেছেন এটাই আমি দেখিয়েছিলাম। এটি আপনার কীগুলির উপর আপনার যে জ্ঞান রয়েছে তার উপর নির্ভর করে।
ম্যাথিউউ

@ ম্যাথিউউ আঃ আমি কি বলতে চাইছি তা দেখতে পাচ্ছি। আমি মনে করি যে @ আরুতাকু বলতে যা বোঝায় তা হ'ল যখন আপনি 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

আপনি আপনার মূল বস্তুটি এরকম কিছু তৈরি করতে পারেন:

পাবলিক ক্লাস ম্যাপকি {

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>();
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.