web-dev-qa-db-ja.com

HashMapのキーとしてのArrayList

ArrayListHashMapのキーとして追加することは可能ですか?バイグラムの出現頻度を保持したい。バイグラムが鍵であり、値はその頻度です。

「彼は」のようなバイグラムごとに、ArrayListを作成してHashMapに挿入します。しかし、正しい出力が得られません。

public HashMap<ArrayList<String>, Integer> getBigramMap(String Word1, String Word2) {
    HashMap<ArrayList<String>, Integer> hm = new HashMap<ArrayList<String>, Integer>();
    ArrayList<String> arrList1 = new ArrayList<String>();
    arrList1 = getBigram(Word1, Word2);
    if (hm.get(arrList1) != null) {
        hm.put(arrList1, hm.get(arrList1) + 1);
    } else {
        hm.put(arrList1, 1);
    }
    System.out.println(hm.get(arrList1));
    return hm;
}


public ArrayList<String> getBigram(String Word1, String Word2) {
    ArrayList<String> arrList2 = new ArrayList<String>();
    arrList2.add(Word1);
    arrList2.add(Word2);
    return arrList2;
}
19
thetna

はい、あなたはハッシュマップのキーとしてArrayListsを持つことができますが、それは可変であるため非常に悪い考えです。

ArrayListを何らかの方法(またはその要素のいずれか)で変更すると、キーは挿入時のhashCodeと同じにならないため、マッピングは基本的に失われます。

経験則では、不変のデータ型のみをハッシュマップのキーとして使用します。 Alex Stybaevによって提案されているように、おそらく次のようなBigramクラスを作成する必要があります。

final class Bigram {

    private final String Word1, Word2;

    public Bigram(String Word1, String Word2) {
        this.Word1 = Word1;
        this.Word2 = Word2;
    }

    public String getWord1() {
        return Word1;
    }

    public String getWord2() {
        return Word2;
    }

    @Override
    public int hashCode() {
        return Word1.hashCode() ^ Word2.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        return (obj instanceof Bigram) && ((Bigram) obj).Word1.equals(Word1)
                                       && ((Bigram) obj).Word2.equals(Word2);
    }
}
26
aioobe

ドキュメント から:

注:可変オブジェクトをマップキーとして使用する場合は、細心の注意を払う必要があります。オブジェクトがマップ内のキーであるときにequals比較に影響を与える方法でオブジェクトの値が変更された場合、マップの動作は指定されません。この禁止事項の特殊なケースとして、マップ自体をキーとして含めることは許可されていません。マップがそれ自体を値として含むことは許容されますが、極端な注意が必要です。equalsメソッドとhashCodeメソッドは、このようなマップで適切に定義されなくなりました。

可変オブジェクトhashCodeequalsのためにキーとして使用する場合は注意が必要です。

結論としては、不変オブジェクトをキーとして使用する方が良いということです。

2

なぜあなたはこのようなものを使用できないのですか?

class Bigram{
    private String firstItem;
    private String secondItem;

    <getters/setters>

    @Override
    public int hashCode(){
        ...
    }

    @Override 
    public boolean equals(){
        ...
    }
}

限られた数のアイテム(2つ)に動的コレクションを使用する代わりに。

2
Alex Stybaev

私はこの解決策を思いつきました。たとえば、ハッシュコードのint容量をオーバーしたり、list.clone()の複雑化など、すべてのケースで明らかに使用できるわけではありません(入力リストが変更された場合、キーは意図したとおりに変わりませんが、Listのアイテムが変更可能で、複製された場合リストはその項目への同じ参照を持ち、その結果、キー自体が変更されます)。

import Java.util.ArrayList;

public class ListKey<T> {
    private ArrayList<T> list;

    public ListKey(ArrayList<T> list) {
        this.list = (ArrayList<T>) list.clone();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;

        for (int i = 0; i < this.list.size(); i++) {
            T item = this.list.get(i);
            result = prime * result + ((item == null) ? 0 : item.hashCode());
        }
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        return this.list.equals(obj);
    }
}

---------
    public static void main(String[] args) {

        ArrayList<Float> createFloatList = createFloatList();
        ArrayList<Float> createFloatList2 = createFloatList();

        Hashtable<ListKey<Float>, String> table = new Hashtable<>();
        table.put(new ListKey(createFloatList2), "IT WORKS!");
        System.out.println(table.get(createFloatList2));
        createFloatList2.add(1f);
        System.out.println(table.get(createFloatList2));
        createFloatList2.remove(3);
        System.out.println(table.get(createFloatList2));
    }

    public static ArrayList<Float> createFloatList() {
        ArrayList<Float> floatee = new ArrayList<>();
        floatee.add(34.234f);
        floatee.add(new Float(33));
        floatee.add(null);

        return floatee;
    }

Output:
IT WORKS!
null
IT WORKS!
1
Javo

これを試してください、これは機能します。

 public Map<List, Integer> getBigramMap (String Word1,String Word2){
    Map<List,Integer> hm = new HashMap<List, Integer>();
    List<String> arrList1 = new ArrayList<String>();
    arrList1 = getBigram(Word1, Word2);     
    if(hm.get(arrList1) !=null){
        hm.put(arrList1, hm.get(arrList1)+1);
    }
    else {
        hm.put(arrList1, 1);
    }

    System.out.println(hm.get(arrList1));
    return hm;
}
1
vikiiii

もちろん可能です。あなたのputに問題があると思います。バイグラムのキーを取得してインクリメントし、このバイグラムのエントリを削除して、更新された値を挿入してください

0
mishadoff