I have a HashMap like below:
map.put("1","One"); \\KV1
map.put("3","Three"); \\KV2
map.put("2","Two"); \\KV3
map.put("5","Five"); \\KV4
map.put("4","Four"); \\KV5
Is there any function where I can get top 3(KV1,KV2,KV3) or bottom 3(KV3,KV4,KV5) key-value pairs? or may be any function by which I can delete top n or bottom n elements?
Thanks in advance.
You can remove n elements from a map without iteration this way
map.keySet().removeAll(Arrays.asList(map.keySet().toArray()).subList(0, 5));
There are some terrible answers to this question.
Firstly, it depends what you mean by top. Insertion order or natural sorted order?
A LinkedHashMap preserves insertion order. A TreeMap maintains its keys in natural sorted order.
If it's a sorted map, then you can request a view of the keys using Treemap.headMap(K key), tailMap() and subMap();
If it's insertion order then you'll have to extract the submap yourself. Guava provides a helper in Maps called Maps.filterKeys that will allow you to view the underlying map fltered by a Predicate you pass in. This is useful if you don't want to copy the map, just view it differently. Of course, you can always copy the resultant map if that's what you want or roll your own more specialised case.
This question shows how to write a generic subMap method for LinkedHashMaps.
LinkedHashMap maintains a linked list of the entries in the map, in the order in which they were inserted.
Map<String,String> map = new LinkedHashMap<String, String>();
map.put("1","One"); //KV1
map.put("3","Three"); //KV2
map.put("2","Two"); //KV3
map.put("5","Five"); //KV4
map.put("4","Four"); //KV5
for(Map.Entry<String, String> mapentry : map.entrySet() ){
System.out.println(mapentry.getKey()); // you can get the keys and values
System.out.println(mapentry.getValue());
}
Maybe this can work for skipping n elements at the end of list, limit here is (n-m) where m is the number of elements to be skipped at the bottom of the list
items.entrySet().stream()
.limit(limit)
.collect(LinkedHashMap::new, (m, e) -> m.put(e.getKey(), e.getValue()), Map::putAll );
Or you can use skip to ignore elements at the start of the map, where skipElements here is the number of elements that you want to skip in the beginning of the list,
items.entrySet().stream()
.skip(skipElements)
.collect(LinkedHashMap::new, (m, e) -> m.put(e.getKey(), e.getValue()), Map::putAll );
I haven't tested this.
Use a SortedMap, such as a TreeMap instead of a HashMap. You can then iterate through the keys in order. That makes it possible to find and delete the 3 smallest keys. Delete the three largest key by finding and then deleting the last key three times.
Related
In a graph i associate a node to a quantity : quantities could be redundant and nodes can't, so in order to sort according to ascending quantities i put nodes as keys and quantities as values of a LinkedHashMap and sort it as follows :
LinkedHashMap<Node, Integer> orderedResult = mapNameToSize.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
But my question is how to get the keys sorted accordingly into a ArrayList?
If all you want is your keys in order of value then you can replace your code with:
List<Node> sortedNodes =
mapNameToSize
.entrySet()
.stream()
.sorted(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.collect(Collectors.toList())
;
Using the ArrayList copy constructor with the LinkedHashMap's keySet will return an ArrayList with elements in the same order as the LinkedHashMap's entries:
List<Node> orderedKeys = new ArrayList<>(orderedResult.keySet())
As mentioned in another answer, you could alternatively sort the initial map's entries within a stream and collect its values into a list. This is a good solution if all you want is the values, and don't also need the LinkedHashMap.
However, if you already have an ordered LinkedHashMap and you want to get its keys in the same order as the map, it probably makes more sense to use to use the existing map's key set than to re-sort the source and stream to a list. Additionally, this will work even if there is no corresponding comparison ordering for the LinkedHashMap (e.g. it's ordered according to arbitrary insertion order, whereas the stream approach requires a well-defined comparison operation..
I am sending result in descending order but I get output with ascending order
List<myEntity> myData = new ArrayList<>();
Map<Integer,List<myEntity>> myid = new LinkedHashMap<>();
try {
myData = myService.getData(id);
myid = myData.stream().collect(Collectors.groupingBy(myEntity::getDataId));
Here mydata is sorted by desc order but after creating collections by group data id my list get sorted with ascending order. I want my collection list to be descending order not ascending order.
As #Holger described in Java 8 is not maintaining the order while grouping
, Collectors.groupingBy() returns a HashMap, which does not guarantee order.
Here is what you can do:
myid = myData.stream()
.collect(Collectors.groupingBy(MyEntity::getDataId,LinkedHashMap::new, toList()));
Would return a LinkedHashMap<Integer, List<MyEntity>>. The order will also be maintained as the list used by collector is ArrayList.
Collectors.groupingBy returns a HashMap without any order as such (as to why you see "some order" is explained here). The correct way to do this is to specify the Map that preserve the order inside the Collectors.groupingBy:
myData.stream()
.collect(Collectors.groupingBy(
MyEntity::getDataId,
LinkedHashMap::new,
Collectors.toList()
))
collect(Collectors.groupingBy()) returns a new Map which overwrites the variable to your previous LinkedHashMap. Your initial assignment is therefore futile. The exact type returned is undefined by the specs but in my test run it returned a HashMap. (Never assume this will always be the case across different versions and brands of Java!)
But the main issue is that you're storing Integer as keys. If the values of those keys is smaller than the modulus of the table inside the HashMap, they will just appear ordered (because the hashCode of an Integer is just it;s value). When I tested with 1000 Integer values of 0..999, the hashtable (the array as part of the inner workings of HashMap) appeared to be of size 2048. (Again, undocumented so don't assume it!)
In summary, the reason you see the results in ascending order is because of an implementation artifact, not because there's a specific reason.
You need reverse order of map. So In java 8 , i solved with this.
myData = myService.getData(id);
myid = myData.stream().collect(Collectors.groupingBy(myEntity::getDataId));
Map<Integer, List<myEntity>> finalMap = new LinkedHashMap<>();
myid.entrySet().stream()
.sorted(Map.Entry.<Integer, List<myEntity>>comparingByKey()
.reversed())
.forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));
System.out.println("FINAL RESULT : " + finalMap);
Entryset gives us Integers of this map of myid. So sort and get from first map which is myid and put in finalMap
I have a sorted map and would like to retrieve the values in the order of their corresponding keys. I.e. if my sorted map has (1,6), (2,4), (3,1), I want to retrieve [6,4,1].
Is there something faster than iterating over the sorted map like so?
SortedMap<Double, Double> sortedMap = new TreeMap<Double, Double>(sortedMap.size());
List<Double> values = new ArrayList<Double>();
for (Entry<Double, Double> entry : sortedMap.entrySet()) {
values.add(entry.getValue());
}
I don't think simply doing:
values = new ArrayList<Double>(sortedMap.values())
would work since sortedMap.values() returns a Collection with no guarantees on the order but iterating over the map doesn't strike me as efficient.
sortedMap.values() returns a Collection with no guarantees on the order
According to docs for SortedMap the order is guaranteed, see:
http://docs.oracle.com/javase/7/docs/api/java/util/SortedMap.html#values()
Why do you think iterating over a sorted map is slow? In order to retrieve all the values you would have to eventually iterate through the entire Map. So the time complexity will always be O(n).
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.
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