Search code examples
javaalgorithmsetobject-comparison

Java: Better way to compare sets of 2 numbers than concatenation


Here's the situation: I want to test 2 objects for uniqueness based on 2 different ID's. Example:

// 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
}

In the Example, Objects A and B are the same because id_a and id_b are the same, and Object C is different.

To determine this in the code, I'm planning on converting both ID's to a string and concatenating them together with a separator char in the middle (e.g., "{id_a},{id_b}"), then adding them to a Set<String> to test for uniqueness.

My question is, is there a better way? (By better, I mean more efficient and/or less kludgy)


Solution

  • If you want to use HashSet, you can override hashCode and equals to exclusively look at those two members.

    Hash code: (31 is just a prime popularly used for hashing in Java)

    return 31*id_a + id_b;
    

    Equals: (to which you'll obviously need to add instanceof checks and type conversion)

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

    If you don't want to bind these functions to the class because it's used differently elsewhere, but you still want to use HashSet, you could consider:

    • Creating an intermediate class to be stored in the set, which will contain your class as a member and implement the above methods appropriately.

    • Use your string approach

    • Use HashSet<Point> - Point is not ideal for non-coordinate purposes as the members are simply named x and y, but I do find it useful to have such a class available, at least for non-production code.


    Alternatively, if you want to use TreeSet, you could have your class implement Comparable (overriding compareTo) or provide a Comparator for the TreeSet, both of which would compare primarily on the one id, and secondarily on the other.

    The basic idea would look something like this:

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