简体   繁体   English

在Java中将多个行列式映射到值的最佳方法

[英]Best way to map multiple determinants to a value in Java

I have a requirement in which I need to map multiple determinants to values. 我有一个需要将多个行列式映射到值的要求。

  • Each set of determinants in a given job execution is guaranteed to be unique. 给定作业执行中的每组决定因素都保证是唯一的。 The value to be determined doesn't have to be unique but it probably is. 要确定的值不必是唯一的,但可能是唯一的。

  • Depending on the input to the job execution, this could be either one key, or the combination of two keys, or the combination of n keys that will be mapped to a single value. 根据作业执行的输入,它可以是一个键,也可以是两个键的组合,也可以是将映射到单个值的n键的组合。 In practice this n will probably be limited to no more than 5, although it is possible it could exceed that. 实际上,该n可能会限制为不超过5,尽管有可能超过该数量。

  • Each job execution will have a set number of determinants for all inputs (Ie, all inputs will have either 2 determinants, 3 determinants, or n determinants, and will not have a mix). 每个作业执行将对所有输入具有固定数量的行列式(即,所有输入将具有2个行列式,3个行列式或n个行列式,并且不会混合使用)。

One key example: foo --> bar 一键示例: foo --> bar

Two keys: foo, bar --> baz 两个键: foo, bar --> baz

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

Prior to this, the requirement was that I would only ever map two values to another value. 在此之前,要求我只将两个值映射到另一个值。 I created an immutable Key class with two member variables and the appropriate override of equals and hashCode . 我创建了一个不可变的Key类,它具有两个成员变量以及equalshashCode的适当替代。

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

However, now that I may be dealing with n number of values, I want to take a look at using a list as the key. 但是,既然我可能正在处理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"));

This question reminds me that it is bad to use a mutable object (like a List) as a key in a map. 这个问题提醒我,将可变对象(如List)用作映射中的键是很不好的。 However, in my application, the key is only set once and is never altered. 但是,在我的应用程序中,密钥仅设置一次,并且从未更改过。 Here is an alternative from this question that forces it to be immutable: 这是该问题的另一种选择,迫使它是不可变的:

HashMap<List<String>, String> map;

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

In addition, I could always make a class like the following to prevent mutations on the list: 另外,我总是可以制作一个如下所示的类来防止列表上的突变:

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"));

Using a plain array as the key won't work, because an array's equal method only checks for identity: 使用纯数组作为键将不起作用,因为数组的equal方法仅检查身份:

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

That could be fixed by the following: 可以通过以下方法解决此问题:

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

How about concatting all the determinants together in a string? 将所有行列式汇总到一个字符串中怎么样?

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() {
        //...
    }
}

Which one of these solutions (or another one that I did not propose) is the best suited for these requirements? 这些解决方案中的哪一个(或我没有提出的另一种)最适合这些要求?

As a comment, your question includes too much details and could have been way shorter. 作为注释,您的问题包括太多细节,可能更短。 Now comes my answer. 现在是我的答案。

I prefer using a wrapper class that completely hides the representation of the class. 我更喜欢使用一个完全隐藏该类表示形式的包装器类。 One thing you can do as a small optimization is storing the hashCode of your keys to prevent computing it every time. 作为小型优化,您可以做的一件事是存储密钥的hashCode,以防止每次对其进行计算。 The equals method will be called more rarely (each collision in the map) and you can't do much about it : 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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM