Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Having a Multimap sorted on keys only in Java

Tags:

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 
like image 861
Olivier Grégoire Avatar asked Mar 31 '11 14:03

Olivier Grégoire


People also ask

Can you sort a Multimap?

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

Is map sorted according to key?

The map is sorted according to the natural ordering of its keys.

Does Multimap maintain order?

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.

Are map keys sorted Java?

Ascending Order. By default, all key-value pairs in TreeMap are sorted in their natural order.


2 Answers

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.

like image 165
ColinD Avatar answered Dec 04 '22 23:12

ColinD


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

like image 25
gdejohn Avatar answered Dec 04 '22 23:12

gdejohn