Java:更好地比较2个数字的集合而不是连接

时间:2014-04-29 20:48:46

标签: java algorithm set object-comparison

以下是这种情况:我想基于2个不同的ID测试2个对象的唯一性。例如:

// Note I'm using JSON notation to keep things simple; the actual code 
// is with Java Objects

// OBJECT A
{
    main_id: 0,
    id_a: 123,
    id_b: 456
}

// OBJECT B
{
    main_id: 1,
    id_a: 123,
    id_b: 456
}

// OBJECT C
{
    main_id: 2,
    id_a: 123,
    id_b: 789
}

在示例中,对象A和B是相同的,因为id_aid_b是相同的,而对象C是不同的。

要在代码中确定这一点,我打算将ID转换为字符串,并将它们与中间的分隔符char连接在一起(例如"{id_a},{id_b}"),然后将它们添加到{{1测试唯一性。

我的问题是,有更好的方法吗?(更好的是,我的意思是更有效率和/或更少kludgy

3 个答案:

答案 0 :(得分:2)

如果您想使用HashSet,可以覆盖hashCodeequals,专门查看这两位成员。

哈希代码:(31只是Java中用于散列的一个主要版本)

return 31*id_a + id_b;

等于:(您显然需要添加instanceof支票并输入转化次数)

return id_a == other.id_a && id_b == other.id_b;

如果您不想将这些函数绑定到类,因为它在其他地方使用的方式不同,但您仍想使用HashSet,则可以考虑:

  • 创建一个存储在集合中的中间类,它将您的类作为成员包含,并适当地实现上述方法。

  • 使用字符串方法

  • 使用HashSet<Point> - Point不适合非协调用途,因为成员只需命名为xy,但我觉得它很有用有这样一个类,至少对于非生产代码。


或者,如果您想使用TreeSet,您可以让您的班级实施Comparable(覆盖compareTo)或为Comparator提供TreeSet ,两者都主要在一个id上进行比较,其次在另一个id上进行比较。

基本思想看起来像这样:

if (objectA.id_a != objectB.id_a)
  return Integer.compare(objectA.id_a, objectB.id_a);
return Integer.compare(objectA.id_b, objectB.id_b);

答案 1 :(得分:2)

不确定这是否更高效或更少kludgy。你可以使用主id(根据你的注释)保留原始的hashcode / equals,然后创建一个包含复合ida,idb的hashcode / equals的包装器。也许你需要的东西超过顶部。

CompositeIdEntity.java

public interface CompositeIdEntity {

    long getIdA();

    long getIdB();

}

Entity.java

public class Entity implements CompositeIdEntity {

    private final long mainId;

    private final long idA;

    private final long idB;

    public Entity(long mainId, long idA, long idB) {
        this.mainId = mainId;
        this.idA = idA;
        this.idB = idB;
    }

    @Override
    public long getIdA() {
        return idA;
    }

    @Override
    public long getIdB() {
        return idB;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (mainId ^ (mainId >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Entity other = (Entity) obj;
        if (mainId != other.mainId)
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Entity [mainId=" + mainId + ", idA=" + idA + ", idB=" + idB
                + "]";
    }

}

CompositeIdWrapper.java

public class CompositeIdWrapper {

    private final CompositeIdEntity compositeIdEntity;

    public CompositeIdWrapper(CompositeIdEntity compositeIdEntity) {
        this.compositeIdEntity = compositeIdEntity;
    }

    public CompositeIdEntity getCompositeIdEntity() {
        return compositeIdEntity;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + (int) (compositeIdEntity.getIdA() ^ (compositeIdEntity
                        .getIdA() >>> 32));
        result = prime * result
                + (int) (compositeIdEntity.getIdB() ^ (compositeIdEntity
                        .getIdB() >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        CompositeIdWrapper other = (CompositeIdWrapper) obj;
        if (compositeIdEntity.getIdA() != other.compositeIdEntity.getIdA())
            return false;
        if (compositeIdEntity.getIdB() != other.compositeIdEntity.getIdB())
            return false;
        return true;
    }

}

Test.java

import java.util.HashSet;
import java.util.Set;

public class Test {

    public static void main(String[] args) {
        Entity en1 = new Entity(0, 123, 456);
        Entity en2 = new Entity(1, 123, 456);
        Entity en3 = new Entity(2, 123, 789);
        Entity en4 = new Entity(2, 123, 456);
        Entity en5 = new Entity(1, 123, 789);

        // Set based on main id
        Set<Entity> mainIdSet = new HashSet<>();
        mainIdSet.add(en1);
        mainIdSet.add(en2);
        mainIdSet.add(en3);
        mainIdSet.add(en4);
        mainIdSet.add(en5);

        System.out.println("Main id set:");
        for (Entity entity : mainIdSet) {
            System.out.println(entity);
        }

        // Set based on ida, idb
        Set<CompositeIdWrapper> compositeIdSet = new HashSet<>();
        compositeIdSet.add(new CompositeIdWrapper(en1));
        compositeIdSet.add(new CompositeIdWrapper(en2));
        compositeIdSet.add(new CompositeIdWrapper(en3));
        compositeIdSet.add(new CompositeIdWrapper(en4));
        compositeIdSet.add(new CompositeIdWrapper(en5));

        System.out.println("Composite id set:");
        for (CompositeIdWrapper wrapped : compositeIdSet) {
            System.out.println(wrapped.getCompositeIdEntity());
        }

    }

}

输出

Main id set:
Entity [mainId=1, idA=123, idB=456]
Entity [mainId=2, idA=123, idB=789]
Entity [mainId=0, idA=123, idB=456]
Composite id set:
Entity [mainId=0, idA=123, idB=456]
Entity [mainId=2, idA=123, idB=789]

答案 2 :(得分:1)

看到这一点,在这里我重写了equals()和hashcode()以确保&#34; name&#34;的唯一性。 Person对象的字段

public class SetObjectEquals {
    Person p1 = new Person("harley");
    Person p2 = new Person("harley");

    public void method1() {
        Set<Person> set = new HashSet<Person>();
        set.add(p1);
        set.add(p2);
        System.out.println(set);
    }

    public static void main(String[] args) {
        SetObjectEquals obj = new SetObjectEquals();
        obj.method1();
    }

}

class Person {
    String name;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    Person(String name) {
        this.name = name;
    }
}