I using a Guava MultiMap (impl LinkedListMultimap) to allow me to store multiple values for a key, but then I want to sort the map by the highest value and return the keys.
i.e
After first run I have
key1:{13}
key2:{7}
key3:{11}
After second run I now have
key1:{13,14}
key2:{7,18}
key3:{11,1}
After third run I now have
key1:{13,14,16}
key2:{7,18,6}
key3:{11,1,22}
I want an order of
key3
key2
key1
and I want to output the keys (I dont need to know the values any longer)
I cant work out a way to do that, I dont have to use MultiMap it just looked like it might help
If I were you, I'd start by not using a Multimap, but rather, using a Map to track the greatest value associated with each key. Then, you have a Map<String, Integer>, and if you don't need to save the Map afterwards, then I'd do something like
final Map<String, Integer> map = ...
return Ordering.natural().onResultOf(Functions.forMap(map)).reverse()
// a comparator to compare strings in descending order of their
// associated values
.immutableSortedCopy(map.keySet());
To unpack a bit:
Ordering.natural() // the natural ordering on integers
.onResultOf(
Functions.forMap(map) // use the Map<String, Integer> as a Function
// this ordering now compares Strings by the natural ordering of
// the integers they're mapped to
.reverse(); // reverses the ordering, so it now sorts in descending order
What I would do is stick the entrySet into a TreeSet with a custom comparator. Then pull out the keys.
sortedEntries = Sets.newTreeSet(comparator).addAll(multimap.entries());
return Collections2.transform(sortedEntries, keyExtractor);
The implementation of keyExtractor, comparator and parametrization is left as an exercise to the reader.
Related
With a LinkedHashMap, when I try to reinsert same key with different value, it replaces the value and maintains the order of key i.e if I do this
Map<String,String> map = new LinkedHashMap<>();
map.put("a", "a");
map.put("b", "b");
map.put("c", "c");
map.put("d", "d");
map.values().stream().forEach(System.out::print);
Output: abcd
Now if I add in the map a different value with same key,the order remains the same i.e
map.put("b", "j");
map.values().stream().forEach(System.out::print);
Output: ajcd
Is there any other way? One is to remove and reinsert key with new value, which prints acdj as output. In my case I want to do it for multiple keys based on some property of object used as value?
Solution using streams would be preferable.
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
LinkedHashMap javadoc.
it keep track of the keys insertion, and if we add the Map.put javadoc :
If the map previously contained a mapping for the key, the old value is replaced by the specified value.
Map javadoc
The Entry is not replace, only the value is modified so the key remains the same.
You need to remove and then insert the value to update the ordering of the keys.
A HashMap is not sorted by either keys or values. What you are looking for is a TreeMap.
For a HashMap, the only guarantee is, that the keys are hashed and put in an array, based on their hash.
The LinkedHashMap, according to the Javadoc, creates an internal LinkedList, and tracks the original insertion order of entries. In other words, if you use LinkedHashMap, you won't, necessariely receive a 'sorted' list at all.
You have two options to work around this: Either use a TreeMap (or derivate thereof), or sort every time, you want to output the values. TreeMaps have an internal sorting, based on their keys. If the keys are compared to each other the way you'd expect (by comparing the Strings) then you get a properly ascending sorting, based on the keys. However this does not solve your problem, that you want to sort the values.
To solve your original problem, use a bidirectional TreeMap. Apache Commons4 implements such a map (https://commons.apache.org/proper/commons-collections/javadocs/api-4.3/org/apache/commons/collections4/bidimap/AbstractDualBidiMap.html#values--)
It allows you to access both a key and a value set. But be aware that this map will not work for you, if your values are not unique. Like keys, all values in a bidirectional map need to be unique, because they need to serve as keys themselves.
From the Javadoc:
This map enforces the restriction that there is a 1:1 relation between keys and values, meaning that multiple keys cannot map to the same value. This is required so that "inverting" the map results in a map without duplicate keys. See the put(K, V) method description for more information.
Hashmap insertion is based on hashcode only. For example a key of "b" has a hashcode as 98.
for map.put("b", "b");
you inserting as a key "b" which has hascode 98.
so it will look like. 98 ---> holds value 'b'.
again if you try to put on same key "b" which has a hashcode 98 only.
so hashmap try to link on same hashcode only which is 98 ---> holds "j" as a value.
for know working of hashmap hashcode check out below link
https://www.geeksforgeeks.org/internal-working-of-hashmap-java/
I have a HashMap defined as such:
public Map<Integer, String> staticBlockPositions = new HashMap<Integer, String>();
I am iterating over the map by getting each key, like this:
for (Integer key : blockPositions.keySet()) {
System.out.println(key);
}
My question is, can I rely on the value of key to always be in ascending order. So if my HashMap looks something like this:
{
4: "abc123",
1: "def456",
11: "qwe789",
10: "iop019"
}
(I know this is JSON format, this is just so you get an idea of the data set).
Will my loop always output
1
4
10
11
regardless of the order of my data?
Important to note, the order in which the keys are add is completely random, and I cannot control what key is added when.
This is for a Tetris style game, so getting the keys in ascending order is a must.
Quoting the Javadoc:
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.
There is no special case for integer keys. You simply can't rely upon the order.
If you want the keys to be in ascending order, use an implementation of SortedMap, like TreeMap.
In addition to what #AndyTurner stated about HashMap not guaranteeing order, it appears that TreeMap provides the functionality you are looking for.
No,
To maintain sorted order, use TreeMap.
To maintain insertion order, use LinkedHashMap.
I want to get the first value from my HashMap while I do not know the key for the value.
Is it possible? Are there are libraries to do this?
You could use a java.util.LinkedHashMap<K, V>. Then you can iterate through the map in insertion order.
To only get the first entry you can use an iterator:
Map<String, String > map = new LinkedHashMap<String, String >();
// ... fill the map
Entry<String, String > next = map.entrySet().iterator().next();
next.getKey();
next.getValue();
If you want the first key that you inserted into the map, then use LinkedHashMap. It's basically a HashMap that remembers the order in which things were inserted, so you can iterate them in the original order.
If you want to select the first key in the natural ordering of the key class; or if you want to select the first key under some ordering of your own, then use TreeMap. It's a type of map that sorts things as you insert them into the map. You can set up a TreeMap with its own Comparator, if you want to specify the order in which the keys are sorted. If you don't supply a Comparator when you create a TreeMap, then it will sort the keys by their natural order.
I recommend reading the Javadocs for both TreeMap and LinkedHashMap before you decide which of the two is appropriate for your application.
Use a LinkedHashMap or TreeMap to maintain insertion order in the first place, after that it is just a matter of using the Iterator.
You can do something like this.
Iterator it = map.entrySet().iterator();
while (it.hasNext()) {
//This will be your very first element
Map.Entry pairs = (Map.Entry)it.next();
System.out.println(pairs.getKey() + " = " + pairs.getValue());
}
I searched the web(and Stackoverflow) a lot but couldn't exactly found what I was looking for. Also couldn't really understand the concept.
As a Java assignment I have a treeMap storing some values in it.
static Map<String, Double> customers = new TreeMap<String, Double>();
Naturally it stores them ascending by it's String values. But I want it to store it's values ascending by it's Double values. How can I achieve this by a comparator? Details would be much appreciated.
Also again in this assignment I've another, separate treeMap which stores different values. Again declared like below:
static Map<String, Double> customers = new TreeMap<String, Double>();
It's okay for it to store it's values ascending by String. I'm using it like this to print out it's values but I also need to print it's values in ascending order sorted by Double. So how can I re-sort a treeMap. Again, details would be much appreciated.
You cannot re-sort a TreeMap. It has a fixed iteration order, determined at TreeMap construct-time. If you want a different sort order, use a different data structure.
I'm using it like this to print out it's values but I also need to print it's values in ascending order sorted by Double.
So don't worry about sorting the TreeMap. Create a List<Double> of the values in the map, and sort those.
List<Double> values = new ArrayList<Double>(customers.values());
Collections.sort(values);
System.out.println(values);
Make another map:
Map<Double, String> values = new TreeMap<Double, String>();
and always add to both maps (e.g. via a helper method). Unless there are memory constraints, you will get your customers maps sorted by customer and values sorted by whatever the Double value represents.
If you can have duplicate values, you can make a list (or a set, depending on the requirements) of customers instead:
Map<Double, List<String>> values = new TreeMap<Double, List<String>>();
If I have a data structure
Stock
{
String Symbol;
LinkedHashMap<Date,Double> DateForPrice;
}
I know in the LinkedHashMap, I can get the stock price of specific date without traversing the whole list.
However, if I want to iterate through the LinkedHashMap of DateForPrice starting from a specific date, are there any way to do it without traversing the whole list?
LinkedHashMap doesn’t offer a way to start iterating in the middle of its ordered view of the map’s data. Supposing your use case is really that you want all dates after some Date d and to iterate those, then you should probably store your map as a TreeMap. An important distinction here is that LinkedHashMap’s ordering is the insertion-order, and our supposed use-case here is that you want the natural key-order. TreeMaps maintain such a view, sorting the contents of the map by the map’s key.
TreeMaps have the additional benefit of allowing you to create slices of the map based on the key, so you can call tailMap(K k), to return the map with all keys occurring after k. In this case, you can call tailMap with your starting point, d.
e.g.:
TreeMap<Date, Double> dateForPrice;
// load up dateForPrice
Date start = // the point to start your iteration
for(Entry<Date, Double> entry : dateForPrice.tailMap(start).entrySet()){
// loop code
}
tailMap method returns SortedMap, which is not iterable. But it has entrySet method returning Set, which is subinterface of Iterable.
Conveniently, if you want to keep storing your data in a LinkedHashMap you can simply load up a TreeMap with your current instance (with some performance tradeoff, of course):
TreeMap<Date, Double> dateSortedDateForPrice = new TreeMap<Date, Double>(dateForPrice);
I'd suggest to use TreeMap instead - it will be sorted by date and you can use tailMap to get the required portion