ArrayList
をHashMap
のキーとして追加することは可能ですか?バイグラムの出現頻度を保持したい。バイグラムが鍵であり、値はその頻度です。
「彼は」のようなバイグラムごとに、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;
}
はい、あなたはハッシュマップのキーとしてArrayList
sを持つことができますが、それは可変であるため非常に悪い考えです。
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);
}
}
ドキュメント から:
注:可変オブジェクトをマップキーとして使用する場合は、細心の注意を払う必要があります。オブジェクトがマップ内のキーであるときに
equals
比較に影響を与える方法でオブジェクトの値が変更された場合、マップの動作は指定されません。この禁止事項の特殊なケースとして、マップ自体をキーとして含めることは許可されていません。マップがそれ自体を値として含むことは許容されますが、極端な注意が必要です。equals
メソッドとhashCode
メソッドは、このようなマップで適切に定義されなくなりました。
可変オブジェクトをhashCode
とequals
のためにキーとして使用する場合は注意が必要です。
結論としては、不変オブジェクトをキーとして使用する方が良いということです。
なぜあなたはこのようなものを使用できないのですか?
class Bigram{
private String firstItem;
private String secondItem;
<getters/setters>
@Override
public int hashCode(){
...
}
@Override
public boolean equals(){
...
}
}
限られた数のアイテム(2つ)に動的コレクションを使用する代わりに。
私はこの解決策を思いつきました。たとえば、ハッシュコードの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!
これを試してください、これは機能します。
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;
}
もちろん可能です。あなたのput
に問題があると思います。バイグラムのキーを取得してインクリメントし、このバイグラムのエントリを削除して、更新された値を挿入してください