滚动我自己的对象来替换Map <int [],string>&amp;地图<数组列表<字符串>,字符串&GT; </数组列表<字符串> </INT [],字符串>

时间:2015-02-26 13:50:23

标签: java object

我正在尝试使用以下数据结构:

//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()一起顺利工作并且是可变的。

我认为解决方案是编写自己的对象以类似的方式存储该信息,但我以前从未这样做过。怎么做?

1 个答案:

答案 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);
        }
    }