Sort a TreeMap by either Key Or Value - java

Situation:
I have a Map, a TreeMap to be more exact that looks like
TreeMap<String, Integer>
I have to be able to sort it on either the key OR the value in an ascending OR descending way. The result must be a Map like
Map<String, Integer>
Not an ArrayList or anything like that because the rest (read: allot) of my code won't work anymore. I've searched but couldn't find anything that suits my needs. Is this even possible? Double values may not be lost.

If you use two BiMaps which each back each other, then you effectively have one map.
Somthing like:
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
private BiMap<Integer, String> localid = HashBiMap.create();
private BiMap<String, Integer> inverse = localid.inverse();
you can treat each reference, localid & inverse, as their own map, but changes to one are reflected in the other. The only slight downside is that now both the keys and values must be unique, as the values of one are the keys of the other. For most cases this is not a problem.
For sorting it, you can at any time make a local copy which is a treeMap, and that imposes an ordering. E.g.
ImmutableMap.copyOf(Maps.newTreeMap(bimap))
Now if you are never making changes to your map, this will provide a sorted view, and you can do it by either.
EDIT: A TreebasedTable has two keys for each value, and you can sort either keyset with a comparator. I am not sure that this is exactly what you need, here as the keysets are independent, but you might be able to refactor your code slightly to make this a viable solution.

If the map is small and iterating over it is an infrequent operation, one solution would be to just use a HashMap (for lookup speed) and then sort the entries every time you iterate.
Another solution, if you do these iterations frequently compared to direct map lookups, and if the values (and not just the keys) are unique, would be to maintain two sorted maps, one <String, Integer> and one <Integer, String>.

Guava has the concept of BiMap. Is that what you're looking for?

A TreeMap's keys are sorted by it's comparable.

Try a SortedMap
A Map that further provides a total ordering on its keys. The map is ordered according to the natural ordering of its keys, or by a Comparator typically provided at sorted map creation time. This order is reflected when iterating over the sorted map's collection views (returned by the entrySet, keySet and values methods). Several additional operations are provided to take advantage of the ordering. (This interface is the map analogue of SortedSet.)

Related

Sort hasmap by value inside of a treemap

I have the following treemap
private TreeMap<Long, HashMap<Long, Entry>> index;
Entry contains:
int tf //count
ArrayList<long> off //positions
For each entry in the treemap, I would like to sort the hashmaps by tf. In the following picture, tf of [3] has a bigger value of tf of [0] so I would like to move it to be at the beggining. How can I do that?
You cannot order a HashMap. Trying to do so breaks the way a HashMap stores and finds the elements added to it
What you are trying to do here (as I understand it) is sorting the treemap by its value, while TreeMap can only sort by its keys. more details here - TreeMap sort by value
You may try writing your own sorting method and store the result of sort in a linkedHashMap instead of Treemap. That way you can be able to access the entries in the exact order you added that to the linkedHashMap.
Note: with each change happening to the original map, you ll need to sort it and move it to a different linkedHashMap. Which is very clumsy.
You may consider using different object model for your program.
I believe the fundamental problem with your question is that HashMaps are not sortable by definition. Secondly, a variable definition that is more generic may prove useful:
private SortedMap<Long, SortedMap<Entry, Long>> index;
Noticed I switched the order of Entry and Long. This is because Maps only sort based on the key. You'd have to either make Entry implement Comparable or provide a custom Comparator when you instantiate that Map.

Why don't TreeMap.values() reflect the order in which elements were originally added?

I need a data structure that will perform both the role of a lookup map by key as well as be able to be convertable into a sorted list. The data that goes in is a very siple code-description pair (e.g. M/Married, D/Divorced etc). The lookup requirement is in order to get the description once the user makes a selection in the UI, whose value is the code. The sorted list requirement is in order to feed the data into UI components (JSF) which take List as input and the values always need to be displayed in the same order (alphabetical order of description).
The first thing that came to mind was a TreeMap. So I retrieve the data from my DB in the order I want it to be shown in the UI and load it into my tree map, keyed by the code so that I can later look up descriptions for further display once the user makes selections. As for getting a sorted list out of that same map, as per this post, I am doing the following:
List<CodeObject> list = new ArrayList<CodeObject>(map.values());
However, the list is not sorted in the same order that they were put into the map. The map is declared as a SortedMap and implemented as a TreeMap:
SortedMap<String, CodeObject> map = new TreeMap<String, CodeObject>().
CodeObject is a simple POJO containing just the code and description and corresponding getters (setters in through the constructor), a list of which is fed to UI components, which use the code as the value and description for display. I used to use just a List and that work fine with respect to ordering but a List does not provide an efficient interface for looking up a value by key and I now do have that requirement.
So, my questions are:
If TreeMap is supposed to be a map in the ordered of item addition, why isn's TreeMap.values() in the same order?
What should I do to fulfill my requirements explained above, i.e. have a data structure that will serve as both a lookup map AND a sorted collection of elements? Will TreeMap do it for me if I use it differently or do I need an altogether different approach?
TreeMap maintain's the key's natural order. You can even order it (with a bit more manipulation and custom definition of a comparator) by the natural order/reverse order of the value. But this is not the same as saying "Insertion order". To maintain the insertion order you need to use LinkedHashMap. Java LinkedHashMap is a subclass of HashMap - the analogy is the same as LinkedList where you maintain the trace of the next node. However, it says it cannot "Guarantee" that the order is maintained, so don't ask your money back if you suddenly see an insertion order is maintained with HashMap
TreeMap's documentation says:
The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.
So unless you're providing a Comparator and tracking the insertion order and using it in that Comparator, you'll get the natural order of the keys, not the order in which the keys were inserted.
If you want insertion order, as davide said, you can use LinkedHashMap:
Hash table and linked list implementation of the Map interface, with predictable iteration order...This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order). Note that insertion order is not affected if a key is re-inserted into the map.
What you need is LinkedHashMap
See another question as well.

Occurred order in the iteration at run-time in a map

In the piece of code similar to
//something before
Iteration<String> iterator = hashMap.keySet().iterator();// HashMap<String, Document>
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//something after
I know that the order of print can be different by the order of insertion of entry key, value; all right.
But if I call this piece in another moment, with re-create the variable hashMap and putting them the equal elements, can the second-moment time print be different from the first-time print?
My question was born by a problem with a web-app: I have a list of String in a JSP, but, after some years, the customer call because the order of the String was different in the morning, but it shows the usual order at the afternoon.
The problem is happened in only one day: the web-app uses the explained piece of code for take a Map and populate an ArrayList.
This ArrayList does'nt any explicit changement of order (no Comparator or similar classes).
I think (hope) that the cause of different order of print derives by a different sequence of iteration in the same HashMap at run-time and I looking for a validation by other people.
In the web, I read that the iteration order by a HashMap changes if the HashMap receives a modification: but what happens if the HashMap remains the same?
Hash map document says HashMap makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
that explains though the hashmap is same it can not guaranatee on order. for Ordered map you can use TreeMap or LinkedHashMap
TreeMap API says The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.
HashMap API documentation states that
This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
For a Map that keeps its keys in original insertion order, use LinkedHashMap.
For a Map that keeps its keys in sorted order (either natural order or by you passing a Comparator), use either TreeMap or ConcurrentSkipListMap. If multi-threaded, use the second.
For a Map where the key an enum, use EnumMap if you want the entries ordered by the definition order of the enum's objects.
The other six Map implementations bundled with Java 11 do not promise any order to their entries.
See this graphic table of mine as an overview.
Use a LinkedHashMap instead, to preserve insertion order. From the javadoc: "Hash table and linked list implementation of the Map interface, with predictable iteration order."
If you just want a Map with predictable ordering, then you can also use TreeMap. However, a LinkedHashMap is faster, as seen here: "TreeMap has O(log n) performance for containsKey, get, put, and remove, according to the Javadocs, while LinkedHashMap is O(1) for each."
As Octopus mentioned, HashMap "makes no guarantees as to the order of the map," and you shouldn't use it if order must remain consistent.

Is there a SortedMultimap type implementation in Guava that doesn't care about the order of its values

E.g. I want a multimap from Integer to zero or more File objects. I'd like the map to stay sorted as I insert or remove entries. But I don't care about the order of the values (Files), which don't have a natural ordering anyway.
There doesn't seem to be an implementation that I can see (which is really unfortunate), so right now I'm stuck using TreeMap<Integer, List<File>>.
MultimapBuilder should be able to do what you want:
SetMultimap<Integer, File> multimap =
MultimapBuilder.treeKeys().hashSetValues().build();

Java HashMap and underlying values() collection

I was wondering if the Collection view of the values contained in a HashMap is kept ordered when the HashMap changes.
For example if I have a HashMap whose values() method returns L={a, b, c}
What happened to L if I add a new element "d" to the map?
Is it added at the end, i.e. if I iterate through the elements, it's the order kept?
In particular, if the addition of the new element "d" causes a rehash, will the order be kept in L?
Many thanks!
I was wondering if the Collection view of the values contained in a HashMap is kept ordered when the HashMap changes.
No, there is no such guarantee.
If this was the case, then the following program would output and ordered sequence from 1-100
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < 100; i++)
map.put(i, i);
System.out.println(map.values());
(and it doesn't).
There is a class that does precisely what you're asking for, and that is LinkedHashMap:
Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).
If it doesn't say it in the JavaDoc then there are no guarantees about it. Different versions of Java could do different things. Don't depend on undocumented behaviour.
You might want to look at LinkedHashMap.
HashMap in Java aren't ordered, so I think it will be safe to say that values() won't return an ordered Collection.
LinkedHashMap is an ordered version of HashMap (insertion order), but I don't know it values() will return an ordered Collection. I think the best is to try.
Generally they is no guarantee of order when you are using HashMap. It might be in the order in which you add elements for a few elements but it would get reshuffled when there is a possibility of collision and it has to go with a collision resolution strategy.

Categories