Search code examples
javatreemap

Java map with tuple as key, remove/get by tuple key


I have scenario where I would like to have a sorted map with a tuple as key:

var scheduledRunnables = new TreeMap<Tuple<Integer, String>, Runnable>(Comparator.comparing(Tuple::getKey));

When adding, I want to add a tuple:

scheduledRunnables.put(new Tuple<>(order, taskName), task);

When sorting, I want it to be sorted by the order integer, since that determines order of execution of the runnables. I do not necessarily know the value of the variable taskName. When calling get, I want to only supply the order integer, because of the same reason as previously stated. When calling put, I want to take the entire pair into consideration. So something like this:

scheduledRunnables.put(new Tuple<>(1, "Some task"), () -> System.out.println("asdf"));
scheduledRunnables.get(1).run(); // Should output 'asdf'
scheduledRunnables.put(new Tuple<>(1, "Some task"), () -> System.out.println("qwerty"));
scheduledRunnables.get(1).run(); // Should output 'qwerty'
scheduledRunnables.remove(1).run(); // Should output 'qwerty' and remove from map

The Tuple class is just a data holder that looks like this:

@Data
public class Tuple<K, V> {

    private final K key;
    private V value;

    public Tuple(K key, V value) {
        this.key = key;
        this.value = value;
    }

}

How would this be implemented? Is is possible without making a custom implementation of the SortedMap interface? Is there a better way to achieve what I am after?


Solution

  • You can just make you value not relevant (its just a meta information). So its not needed for initializing the class (optional parameter) and not taken into account when using hashCode or equals:

    public class Tuple<K extends Comparable<K>, V> implements Comparable<Tuple<K, V>> {
        private final K key;
        private V value;
    
        public Tuple(K key) {
            this.key = key;
        }
    
        public Tuple(K key, V value) {
            this.key = key;
            this.value = value;
        }
    
        public int hashCode() {
            return key.hashCode();
        }
    
        public boolean equals(Object obj) {
            return obj == this || (obj instanceof Tuple) && key.equals(((Tuple) obj).key);
        }
    
        public int compareTo(Tuple<K, V> other) {
            return key.compareTo(other.key);
        }
    }
    

    I've also made Tuple comparable, which will just compare the keys, so you can create your TreeMap without a custom Comparator like this:

    var scheduledRunnables = new TreeMap<Tuple<Integer, String>, Runnable>();
    

    You then can call your get with:

    Runnable runnable = scheduledRunnables.get(new Tuple<>(1));