ArrayList作为HashMap中的键

是否可以添加ArrayList作为HashMap的键。 我想保留双字母的频率数。 二元组是关键,价值在于它的频率。

对于像“他是”这样的每个bigrams,我为它创建一个ArrayList并将其插入到HashMap 。 但我没有得到正确的输出。

 public HashMap<ArrayList, Integer> getBigramMap(String word1, String word2) { HashMap<ArrayList, Integer> hm = new HashMap<ArrayList, Integer>(); ArrayList arrList1 = new ArrayList(); 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 getBigram(String word1, String word2) { ArrayList arrList2 = new ArrayList(); arrList2.add(word1); arrList2.add(word2); return arrList2; } 

是的,您可以将ArrayList作为哈希映射中的键,但这是一个非常糟糕的主意,因为它们是可变的

如果以任何方式(或其任何元素)更改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比较的方式更改对象的值,则不指定映射的行为。 这种禁令的一个特例是,地图不允许将自己作为一个关键词。 虽然允许映射将自身包含为值,但建议极其谨慎: equalshashCode方法不再在这样的映射上很好地定义。

当你使用可变对象作为hashCodeequals密钥时,你必须小心。

底线是最好使用不可变对象作为键。

为什么你不能使用这样的东西:

 class Bigram{ private String firstItem; private String secondItem;  @Override public int hashCode(){ ... } @Override public boolean equals(){ ... } } 

而不是将动态集合用于有限数量的项目(两个)。

试试这个,这会有效。

  public Map getBigramMap (String word1,String word2){ Map hm = new HashMap(); List arrList1 = new ArrayList(); 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; } 

我想出了这个解决方案。 它显然在所有情况下都不可用,例如在步进哈希码int容量或list.clone()并发症时(如果输入列表被更改,键保持与预期相同,但当List的项是可变的时,克隆list对其项目具有相同的引用,这将导致更改密钥本身)。

 import java.util.ArrayList; public class ListKey { private ArrayList list; public ListKey(ArrayList list) { this.list = (ArrayList) 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 createFloatList = createFloatList(); ArrayList createFloatList2 = createFloatList(); Hashtable, 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 createFloatList() { ArrayList floatee = new ArrayList<>(); floatee.add(34.234f); floatee.add(new Float(33)); floatee.add(null); return floatee; } Output: IT WORKS! null IT WORKS! 

当然有可能。 我认为你的问题存在问题。 尝试获取bigram的密钥,增加它,删除带有此bigram的条目并插入更新的值

请检查下面的代码,以了解key是否是Map中的ArrayList以及JVM将如何为输入执行此操作:这里我编写了hashCode和equals方法的TesthashCodeEquals类。

 package com.msq; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; class TesthashCodeEquals { private int a; private int b; public TesthashCodeEquals() { // TODO Auto-generated constructor stub } public TesthashCodeEquals(int a, int b) { super(); this.a = a; this.b = b; } public int getA() { return a; } public void setA(int a) { this.a = a; } public int getB() { return b; } public void setB(int b) { this.b = b; } public int hashCode() { return this.a + this.b; } public boolean equals(Object o) { if (o instanceof TesthashCodeEquals && o != null) { TesthashCodeEquals c = (TesthashCodeEquals) o; return ((this.a == ca) && (this.b == cb)); } else return false; } } public class HasCodeEquals { public static void main(String[] args) { Map, String> m = new HashMap<>(); List list1=new ArrayList<>(); list1.add(new TesthashCodeEquals(1, 2)); list1.add(new TesthashCodeEquals(3, 4)); List list2=new ArrayList<>(); list2.add(new TesthashCodeEquals(10, 20)); list2.add(new TesthashCodeEquals(30, 40)); List list3=new ArrayList<>(); list3.add(new TesthashCodeEquals(1, 2)); list3.add(new TesthashCodeEquals(3, 4)); m.put(list1, "List1"); m.put(list2, "List2"); m.put(list3, "List3"); for(Map.Entry,String> entry:m.entrySet()){ for(TesthashCodeEquals t:entry.getKey()){ System.out.print("value of a: "+t.getA()+", value of b: "+t.getB()+", map value is:"+entry.getValue() ); System.out.println(); } System.out.println("######################"); } } } 

 output: value of a: 10, value of b: 20, map value is:List2 value of a: 30, value of b: 40, map value is:List2 ###################### value of a: 1, value of b: 2, map value is:List3 value of a: 3, value of b: 4, map value is:List3 ###################### 

所以这将检查List中的对象数和对象中的valriabe值。 如果对象的数量相同且实例变量的值也相同,则它将考虑重复键并覆盖该键。

现在,如果我只更改list3上的对象的值

list3.add(new TesthashCodeEquals(2,2));

然后会打印:

  output value of a: 2, value of b: 2, map value is:List3 value of a: 3, value of b: 4, map value is:List3 ###################### value of a: 10, value of b: 20, map value is:List2 value of a: 30, value of b: 40, map value is:List2 ###################### value of a: 1, value of b: 2, map value is:List1 value of a: 3, value of b: 4, map value is:List1 ###################### 

这样它总是检查List中的对象数和对象的实例变量的值。

谢谢

ArrayList.equals()inheritance自java.lang.Object – 因此ArrayList上的equals()独立于列表的内容。

如果要使用ArrayList作为映射键,则需要重写equals()hashcode()以使两个具有相同内容的相同内容的arraylists在调用equals()返回true并返回在调用hashcode()相同的哈希码。

是否有任何特殊原因你必须使用ArrayList而不是说一个简单的String作为键?

编辑:忽略我,正如Joachim Sauer在下面指出的那样,我错了,甚至都不好笑。