将多个决定因素映射到Java

时间:2015-10-02 19:03:05

标签: java arrays dictionary

我有一个要求,我需要将多个决定因素映射到值。

  • 保证给定作业执行中的每组决定因素都是唯一的。要确定的值不必是唯一的,但可能是。

  • 根据作业执行的输入,可以是一个键,也可以是两个键的组合,或者是n键的组合,它们将映射到单个值。在实践中,n可能会限制在不超过5个,但有可能超过5个。

  • 每个作业执行将为所有输入设置一定数量的决定因素(即,所有输入将具有2个决定因素,3个决定因素或n个决定因素,并且不会混合)。

一个关键示例:foo --> bar

两个键:foo, bar --> baz

三个键:foo, bar, baz --> hai

在此之前,要求是我只会将两个值映射到另一个值。我创建了一个不可变的Key类,它包含两个成员变量以及equalshashCode的相应覆盖。

public class Key {
    String determinant0;
    String determinant1;
    public Key(String d0, d1) {
        determinant0 = d0;
        determinant1 = d1;
    }
    // ..
} 

但是,现在我可能正在处理n个值,我想看一下使用列表作为键。

Map<List, String> map = new HashMap<List, String>();
map.put(Arrays.asList("foo", "bar", "baz"), "hai");
String determined = map.get(Arrays.AsList("foo","bar","baz"));
assert (determined.equals("hai"));

这个question提醒我,使用可变对象(如List)作为地图中的键是不好的。但是,在我的应用程序中,密钥只设置一次,永远不会改变。这是question的另一种选择,它强制它是不可变的:

HashMap<List<String>, String> map;

map.put(
    // unmodifiable so key cannot change hash code
    Collections.unmodifiableList(Arrays.asList("foo", "bar", "baz")),
    "hai"
);

此外,我总是可以创建一个类似下面的类来防止列表中的突变:

public class Key {
    List<String> determinants;
    public Key(List<String> determinants) {
        this.determinants = determinants
    }
    @Override
    public boolean equals(Object obj) {
        //...
    }
    @Override
    public int hashCode() {
        //...
    }
}

Key key = new Key(Arrays.asList("foo","bar","baz"));

使用普通数组作为键将不起作用,因为数组的相等方法仅检查标识:

Map<String[], String> map = new HashMap<String[], String>();
String[] key = new String[]{"foo", "bar", "baz"}
map.put(key, "hai");
System.out.println(map.get(key)); // null

可以通过以下方式解决:

public class Key {
    String[] determinants;
    public Key(String... determinants) {
        this.determinants = determinants;
    }
    @Override
    public boolean equals(Object obj) {
        //...
    }
    @Override
    public int hashCode() {
        //...
    }
}

如何将所有决定因素串在一起?

public class Key {
    String hash = "";
    public Key(String... determinants) {
        for (String determinant : determinants) {
            hash += determinant + "_";
        }

    }
    @Override
    public boolean equals(Object obj) {
        //...
    }
    @Override
    public int hashCode() {
        //...
    }
}

这些解决方案中的哪一个(或我未提出的另一个解决方案)最适合这些要求?

1 个答案:

答案 0 :(得分:1)

作为评论,您的问题包含太多细节,可能会更短。现在回答我。

我更喜欢使用完全隐藏类表示的包装类。作为小优化,您可以做的一件事是存储密钥的hashCode,以防止每次都计算它。 equals方法将被更少地调用(地图中的每次碰撞)并且你不能做很多事情:

public class Key {
    private String[] determinants;
    private int hashCode;

    public Key(String... determinants) {
        if (determinants == null || determinants.length == 0) {
            throw new IllegalArgumentException("Please provide at least one value");
        }
        this.determinants = determinants;
        this.hashCode = Objects.hash(determinants);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Key)) return false;
        Key that = (Key) o;
        return Arrays.equals(determinants, that.determinants);
    }

    @Override
    public int hashCode() {
        return hashCode;
    }
}