Collection without duplicates (based on id) but keeps the highest version number

161 Views Asked by At

This seems like something that should have a standard solution, but I can't find what I'm looking for. It's not difficult to implement by hand, but perhaps I'm just missing a tool in my toolbox?

In pseudo-code, I want a set-like collection that, given existing entries

{id_1, v_1}, {id_2, v_2}

on calling addAll() with

{id_1, v_2}, {id_2, v_1}

will be left with

{id_1, v_2}, {id_2, v_2}

i.e. original id_1 gets replaced with more recent version; original id_2 remains because it is more recent than the incoming one.

I had a look through Guava, but nothing jumped out at me. I'm not very familiar with Apache collections, perhaps something can be built out of that?

Thanks all

3

There are 3 best solutions below

4
On BEST ANSWER

You can wrap a map and provide additional methods, that check item version.

Here is put method, for example.

class MyMap<ID, E> extends HashMap<ID, E extends Versioned & HasId<ID>> {

public void put(E elem) {
    if (containsKey(elem.getId()) {
        E exist = get(elem.getId());
        if (elem.version.isGreater(exist.version)) super.put(elem.getId(), elem);
    } else {
        super.put(elem.getId(), elem);
    }
}

I suggest to use Map instead of Set, because of this problem.

2
On

To avoid extending Map you could grow your own quite simply:

class KeepBestMap<K, V> {

    final Map<K, V> map;
    final Comparator<V> compare;

    public KeepBestMap(Map<K, V> map, Comparator<V> compare) {
        this.map = map;
        this.compare = compare;
    }

    public KeepBestMap(Comparator<V> compare) {
        this(new HashMap<>(), compare);
    }

    public KeepBestMap() {
        // A null compare will assume objects are comparable.
        this(null);
    }

    public Map<K, V> getMap() {
        return map;
    }

    public V put(K key, V value) {
        // Put the new one in - note the old one.
        V replaced = map.put(key, value);
        if (replaced != null) {
            // Decide which to keep.
            // If compare not supplied assume items are Comparable.
            if ((compare != null
                    ? // Use it.
                    compare.compare(replaced, value)
                    : // Assume values are comparable - if they are not then an exception will be thrown (like TreeMap).
                    ((Comparable<V>) replaced).compareTo(value)) > 0) {
                // Put the old one back in.
                map.put(key, replaced);
                // Didn't actually replace it in the end.
                replaced = null;
            }
        }
        return replaced;
    }
}
1
On

Sort the list of pairs into ascending version number order, then put in that order into a java.util.HashSet.