6

I need some data structure that I can build from standard collections or using guava. So it should be mutable Map<Enum, V>. Where V is pretty interesting structure.

V requirements:

  • mutable
  • sorted by comparator (with allowing elements such as compare(a, b) == 0) - these is need for iterations
  • set (there is no such a and b, that a.equals(b) == true) - optional

extra optional requirement to map

  • keys should be iterated by their natural order

now it's HashMap<SomeEnum, LinkedList<Entity>> with different stuff like collections.sort() in the code.

Thanks.

Stan Kurilin
  • 15,614
  • 21
  • 81
  • 132

4 Answers4

12

A Sample implementation

Here is a Guava Multimap implementation of the class you need:

First the drawback: it will have to reside in package com.google.common.collect. The makers of guava have in their infinite wisdom made AbstractSortedSetMultimap package scoped.

I will use this enum in all my examples:

public enum Color{
    RED, BLUE, GREEN
};

Constructing the Class

There are six constructors:

  • Empty (Uses a HashMap and natural ordering for values)

    SortedSetMultimap<Color,String> simple = 
        new EnumValueSortMultiMap<Color, String>();
    
  • with a Comparator(V) (Uses a HashMap<K,SortedSet<V>> with the supplied comparator for the values)

    SortedSetMultimap<Color,String> inreverse =
        new EnumValueSortMultiMap<Color, String>(
            Ordering.natural().reverse()
        );
    
  • with a Map<K,SortedSet<V>> (use this if you want to sort keys, pass in a SortedMap implementation)

    SortedSetMultimap<Color,String> withSortedKeys = 
        new EnumValueSortMultiMap<Color, String>(
            new TreeMap<Color, Collection<String>>()
        );
    
  • with a Map<K,SortedSet<V>> and a Comparator<V> (same as above, but values are sorted using custom comparator)

    SortedSetMultimap<Color,String> reverseWithSortedKeys = 
        new EnumValueSortMultiMap<Color, String>(
            new TreeMap<Color, Collection<String>>(),
            Ordering.natural().reverse()
        );
    
  • with a Class<K extends Enum<K>> (uses an EnumMap internally for higher efficiency, natural ordering for values)

    SortedSetMultimap<Color,String> withEnumMap =
        new EnumValueSortMultiMap<Color, String>(
            Color.class
        );
    
  • with a Class<K extends Enum<K>> and a Comparator<V> (same as above, but values are sorted using custom comparator)

    SortedSetMultimap<Color,String> reverseWithEnumMap =
        new EnumValueSortMultiMap<Color, String>(
            Color.class, Ordering.natural().reverse()
        );
    

Source Code

Here's the class:

package com.google.common.collect;

import java.util.Collection;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;

public class EnumValueSortMultiMap<K extends Enum<K>,
    V extends Comparable<? super V>>
    extends AbstractSortedSetMultimap<K, V>{

    private static final long serialVersionUID = 5359491222446743952L;

    private Comparator<? super V> comparator;
    private Class<K> enumType;

    public EnumValueSortMultiMap(){
        this(new HashMap<K, Collection<V>>());
    }

    public EnumValueSortMultiMap(final Comparator<? super V> comparator){
        this(new HashMap<K, Collection<V>>(), comparator);
    }

    public EnumValueSortMultiMap(final Map<K, Collection<V>> map){
        this(map, Ordering.natural());
    }

    public EnumValueSortMultiMap(final Map<K, Collection<V>> map,
        final Comparator<? super V> comparator){
        super(map);
        this.comparator = comparator;
    }

    public EnumValueSortMultiMap(final Class<K> enumClass,
        final Comparator<? super V> comparator){
        this(new EnumMap<K, Collection<V>>(enumClass), comparator);
    }

    public EnumValueSortMultiMap(final Class<K> enumClass){
        this(new EnumMap<K, Collection<V>>(enumClass));
    }

    @Override
    Map<K, Collection<V>> backingMap(){
        return new EnumMap<K, Collection<V>>(enumType);
    }

    @Override
    public Comparator<? super V> valueComparator(){
        return comparator;
    }

    @Override
    SortedSet<V> createCollection(){
        return new TreeSet<V>(comparator);
    }

}

Other ways to do it

UPDATE: I guess the proper Guava way to do it would have been something like this (it uses the SortedArrayList class I wrote in my other answer):

public static <E extends Enum<E>, V> Multimap<E, V> getMap(
    final Class<E> clz){

    return Multimaps.newListMultimap(
        Maps.<E, Collection<V>> newEnumMap(clz),
        new Supplier<List<V>>(){
            @Override
            public List<V> get(){
                return new SortedArrayList<V>();
            }
        }
    );
}
Community
  • 1
  • 1
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
  • Thanks a lot. Probably, I will use it. It's will be perfect if after this answer Kewin'll change AbstractSortedSetMultimap's scope) – Stan Kurilin Dec 03 '10 at 09:30
  • I guess they will eventually. My guess is that they haven't committed themselves to the API yet, so they are only exposing implementation classes. – Sean Patrick Floyd Dec 03 '10 at 09:33
  • @S.P.Floyd - seanizer, I hope it will be. – Stan Kurilin Dec 03 '10 at 09:46
  • @Stas:If they don't change the scope you can make a package named 'com.google.common.collect' in your project and add the class.I tried it and it's working for me. – Emil Dec 03 '10 at 10:16
  • @Emil it works, yes, but it's also a butt-ugly solution. And I'm pretty sure it relies on non-guaranteed classloader behaviors (I would guess a classloader is free to cache physical locations of packages and that mechanism would break if the package exists in multiple places. But I'm not sure about this) – Sean Patrick Floyd Dec 03 '10 at 10:22
  • @S.P.Floyd - seanizer: [SO question](http://stackoverflow.com/questions/4224760/access-package-private-variables-using-reserved-package-name) on this subject. – Emil Dec 03 '10 at 10:51
  • @Emil thanks, but that won't help in this case (there's no way to access a super class in a class definition via reflection, and the endorsed dir approach is very tedious) – Sean Patrick Floyd Dec 03 '10 at 10:59
  • @S.P.Floyd - seanizer: No that's not what i meant .Just check the link's in the second answer on how to patch api's .Not that we should use it just for your info. – Emil Dec 03 '10 at 11:20
  • @Stas have a look at my updated answer. Things are apparently a lot easier than I thought... – Sean Patrick Floyd Dec 03 '10 at 15:48
  • @S.P.Floyd - seanizer: Thanks. I should add more +1 ) – Stan Kurilin Dec 03 '10 at 16:11
  • @Stas Thanks for the bounty! That really wasn't necessary though :-) – Sean Patrick Floyd Dec 06 '10 at 15:37
  • 1
    @S.P.Floyd - seanizer, you've done big job. So it's thanks for you) – Stan Kurilin Dec 06 '10 at 15:40
6

If an extra class is too much, you maybe want to use the factory methods of the class Multimaps.

SortedSetMultimap<Color, Entity> set = Multimaps.newSortedSetMultimap(
    new HashMap<Enum, Collection<Entity>>(), 
    new Supplier<TreeSet<Entity>>() {
        @Override
        public TreeSet<Entity> get() {
            return new TreeSet<Entity>(new Comparator<Entity>() {
                @Override
                public int compare(Entity o1, Entity o2) {
                    //TODO implement
                }
            });
        }
});
Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
Olivier Heidemann
  • 1,337
  • 10
  • 14
2

You can use an EnumMap instead of the current HashMap. EnumMaps are more efficient for enum keys. In guava check Multimap [examples].

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
Emil
  • 13,577
  • 18
  • 69
  • 108
0

You need an collection implementation V which is used this way: HashMap<SomeEnum, V>. The above stated requirements affect V (not Entity). Right?

I think a link TreeSet<E> should fullfill your requirents:

  • TreeSet implements the Set interface
  • Sorted by natural order or custom Comparator
  • Elements can be added and removed
remipod
  • 11,269
  • 1
  • 22
  • 25