I would like to have a c.g.c.c.Multimap
that is sorted based on keys only. The values shouldn't be sorted. I've tried to build something with guava's TreeMultimap
, but I can't use it because the value type doesn't implement Comparable
.
public class MyObject /* doesn't implement Comparable */ { private String name; private int score; // Getters/setters are implemented public static Function<MyObject,Integer> myObjectToScore { @Override public Integer apply (MyObject o) { return o.score; } } public static Multimap<Integer,MyObject> indexOnScore(Iterable<MyObject> i) { Multimap<Integer,MyObject> m = Multimaps.index(i, myObjectToScore()); // Do the sort of the keys. return m; } }
I've thought about getting a SortedSet
of the keys, then iterating over each of these keys in the sorted set to fetch the various values, but I was hoping using an existing (yet undiscovered) feature in Guava rather than using this kind of hack.
Note: I won't make MyObject
implement Comparable
because it makes no sense with my actual object.
Example of input/output:
Set<MyObject> s = Sets.newHashSet( new MyObject("a", 2), new MyObject("b", 3), new MyObject("c", 1), new MyObject("d", 3), new MyObject("e", 1) ); // Assuming constructor MyObject(String name, int score) for (Map.Entry<Integer, MyObject> e: MyObject.indexedOnScore(s).entries()) { System.out.printf("%d -> %s%n", e.getKey(), e.getValue().getName()); }
Prints:
1 -> c // or switched with line below 1 -> e 2 -> a 3 -> b // or switched with line below 3 -> d
You cannot do that. Multimap in C++ STL is ordered and the order cannot/must not be changed (I think at the bottom line it is using a balanced binary tree for the keys I think, not sure though).
The map is sorted according to the natural ordering of its keys.
Maps don't keep the order of items. This is the contract of MultiMap s... This is the price to pay for query-in performances. One option is to use Map<String, List<String>> instead.
Ascending Order. By default, all key-value pairs in TreeMap are sorted in their natural order.
Multimaps.index
returns an ImmutableListMultimap
, so you wouldn't be able to sort it after creating it. You could, however, first create a sorted copy of your Iterable<MyObject>
and feed that to Multimap.index
... ImmutableListMultimap
keeps things in the same order it was given them.
public static ImmutableMultimap<Integer, MyObject> indexOnScore(Iterable<MyObject> i) { List<MyObject> sorted = Ordering.natural().onResultOf(myObjectToScore()) .sortedCopy(i); return Multimaps.index(sorted, myObjectToScore()); }
Another option might be to create a TreeMultimap
and use Ordering.arbitrary()
as the Comparator
for the values.
MultimapBuilder
was introduced in Guava 16:
<K extends Comparable<? super K>, V> ListMultimap<K, V> multimap() { return MultimapBuilder.treeKeys().linkedListValues().build(); }
That keeps your keys sorted by their natural order (MultimapBuilder::treeKeys
is also overloaded to accept a custom comparator), and the values associated with each key are maintained in a LinkedList
(ArrayList
and HashSet
are among the other options).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With