我正在尝试使用以下数据结构:
//all the words in each file as index, the label as value
static Map< ArrayList<String> , String > train__list_of_file_words = new HashMap<>();
static Map< ArrayList<String> , String > test__list_of_file_words = new HashMap<>();
//frequency count against global dictionary
static Map< int[] , String > train_freq_count_against_globo_dict = new HashMap<>();
static Map< int[] , String > test_freq_count_against_globo_dict = new HashMap<>();
但我被告知这是非感性的,因为它们不能与equals()一起顺利工作并且是可变的。
我认为解决方案是编写自己的对象以类似的方式存储该信息,但我以前从未这样做过。怎么做?
答案 0 :(得分:5)
由于没有人挺身而出,对你的问题给出了完整的答案,我会试一试:
Map< ArrayList<String> , String >
这种方法的问题是ArrayList<String>
是可变的。例如,请参见此示例:
Map<ArrayList<String>, String> map = new HashMap<>();
ArrayList<String> l = new ArrayList<>();
l.add("a");
l.add("b");
map.put(l, "Hello");
System.out.println(map.get(l)); // "Hello";
l.add("c"); // Mutate key.
System.out.println(map.get(l)); // null (value lost!)
进一步阅读:
Map< int[] , String >
这是可能的,但可能会造成混淆,因为两个数组似乎相等,但彼此不是.equals
。请考虑以下示例:
Map<int[], String> map = new HashMap<>();
int[] arr1 = { 1, 2 };
map.put(arr1, "Hello");
int[] arr2 = { 1, 2 };
System.out.println(map.get(arr2)); // null, since arr1.equals(arr2) == false
因此,要检索以前插入的值,您需要使用与键相同的实例。以上示例仅在您使用map.get(arr1)
时才有效。
您可以按照建议滚动自己的数据结构,以跟踪私有数据结构中的映射。例如,你可以使用Map<List<...>, String>
作为支持结构,但要确保你永远不会改变你在该地图中使用的密钥(例如,通过保持地图私有而永远不会发布对List
的引用 - 键)。
如果您事先知道密钥的大小,可以使用嵌套地图,如下所示:Map<String, Map<String, String>>
。
您可以使用第三方集合库,例如Guava或Apache Commons。他们有一个名为Table
的数据结构。 MultiKeyMap
这两者似乎都符合您的要求。
您可以按照@dasblinkenlight的建议创建一个新的,不可变的密钥对象。 (提醒一句;这是安全的,因为String
是不可变的!)代码可以略微简化如下:
final class StringTuple {
private String[] vals;
public StringTuple(String... vals) {
this.vals = vals.clone();
}
public int hashCode() {
return Arrays.hashCode(vals);
}
public boolean equals(Object obj) {
return (obj instanceof StringTuple)
&& Arrays.equals(vals, ((StringTuple) obj).vals);
}
}