合并地图

时间:2017-11-23 19:23:52

标签: java dictionary duplicates

我有类ID和值,以及从ID到值的映射

public class IDs {

    public TreeSet<Integer> ids;
    public HashSet<IDs> neighbors;
    public static HashSet<IDs> idSet = new HashSet<>();

    private boolean hash;
    private int hashcode;

    public IDs(int id,HashSet<IDs> neighbors) {
        this.ids = new TreeSet<>();
        this.ids.add(id);
        this.neighbors = neighbors;
        idSet.add(this);

        this.hash = false;
        this.hashcode = 0;
    }

    public void addNeighbor(IDs neighbor) {
        this.neighbors.add(neighbor);
        neighbor.neighbors.add(this);
    }

    public static boolean cluster(IDs id1,IDs id2) {
        if (id1.equals(id2))
            return false;
        id1.ids.addAll(id2.ids);
        id2.ids.addAll(id1.ids);
        id2.neighbors.remove(id1);
        id1.neighbors.remove(id2);
        id1.neighbors.addAll(id2.neighbors);
        id2.neighbors.addAll(id1.neighbors);

        id1.hash = false;

        return true;
    }

    @Override
    public String toString() {
        String name = "{";
        for (Integer i:ids)
            name += "Cell " + i + ", ";
        name += "}";
        return name;
    }

    @Override
    public boolean equals(Object obj) {
        IDs o = (IDs) obj;
        return this.ids.containsAll(o.ids) && o.ids.containsAll(this.ids);
    }

    @Override
    public int hashCode() {
        if (this.hash)
            return this.hashcode;
        TreeSet temp = (TreeSet) this.ids.clone();
        int first,hash = 0;
        while (!temp.isEmpty()) {
            first = (int) temp.first();
            temp.remove(temp.first());
            hash = CantorPair(hash,first);
        }
        this.hash = true;
        this.hashcode = hash;
        return hash;
    }

    private int CantorPair(int k1,int k2) {
        return (k1 + k2) * (k1 + k2 + 1) / 2 + k2;
    }

}


class Value{
    Integer value;
}
Map<ID,Value> map = new Map<>();

现在我想将条目合并在一起,新值是旧值的总和,但我创建的是具有重复键和旧值的条目。任何人都知道如何解决这个问题?

EDIT1:我已经覆盖了equals()hashCode(),抱歉没有在此处显示,地图仍然有重复的密钥条目!

EDIT2:我已经上传了班级的完整代码

2 个答案:

答案 0 :(得分:1)

当您的密钥类(hashCode())未覆盖equals(Object o)ID方法时,Java只使用对内存中对象的实际引用(指针地址)来计算值(即检查它是否与类的实例化相同)。这就是你获得重复密钥的原因(Java&#34;认为&#34;所有结果都是唯一的。)

要解决此问题,您需要覆盖两种方法,equals()hashCode()

class ID {
    private String id;

    public String getId() { return id; }
    public String setId(String id) { this.id = id; }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if ((obj == null) || (obj.getClass() != this.getClass()))
            return false;
        // safe cast to ID
        ID test = (ID)obj;
        // is id nullable? if so, you need to make an additional null-check here
        return this.getId().equals(test.getId());
    }

    @Override
    public int hashCode() {
        // is id nullable? if so, you need to make an additional null-check here
        return this.getId().hashCode();
    }

}

请参阅Why do I need to override the equals and hashCode methods in Java?

上述代码可以帮助您将自定义类(ID)用作集合键。但我发现你的问题还有另一个问题:

  

现在我想将条目合并在一起,新值是旧值的总和,

请先尝试自己解决,如果你没有成功,请在这里发布一个显示你努力的问题。你的问题,正如它目前所写,并没有显示你所尝试的内容。

答案 1 :(得分:1)

用作Map键的类需要以一致的方式覆盖hashCodeequals方法。 (简而言之,这意味着如果两个实例按照equals方法相同,那么它们的hashCode方法必须返回相同的值。)

您在equals课程中既不会覆盖hashCode也不会覆盖ID,因此每当您将其用作地图的关键字时,您都会收到意外的结果。

根据值的合并,Map中有一个merge method,这绝对是您正在寻找的。如果您在sum课程中使用了Value方法,则可以按以下方式执行:

class Value {
    Integer value;

    Value sum(Value another) {
        value += another.value;
        return this;
    }
}

Map<ID, Value> map = new HashMap<>(); // Map is an interface, 
                                      // you need an actual implementation

map.merge(someId, someValue, Value::sum);