I have a Map of Long and String - Map which stores my timestamp as the key and value as my data.
Map<Long, String> eventTimestampHolder = new HashMap<Long, String>();
Now I want to get 100 most recent data from the above map by looking at timestamp which is part of key and then keep on adding those data in a List of String. In general populate the 100 most recent data in a List.
What is the best way to do this? Can I use TreeMap here and it will sort my keys basis on the timestamp properly?
In general my timestamp is going to look like this - 1417686422238 and it will be in milliseconds
In case you mean by "recent" recently added, then you can try LinkedHashMap which will maintain the order of insertion. Then you can iterate over the first 100 items.
You can iterate over the map like this:
for(Long key : eventTimestampHolder.keySet()) {
String value = eventTimestampHolder.get(key);
}
For any key that can be sorted, you should use a SortedMap (unless there are other requirements making it unsuitable). A TreeMap is a sorted map. Since you need the most recent k entries, you need the largest keys first. This can be done by going through the k first keys in the map's descendingKeySet as follows, a one-liner in Java-8:
eventTimestampHolder.descendingKeySet().stream().limit(k); // in your case, k = 100
If you want not just the keys, but the values as well, then you could find the k'th key, and then use
// the 2nd arg is a boolean indicating whether the k'th entry will be included or not
eventTimestampHolder.tailMap(kthTimestamp, true);
One thing to remember when using tailMap is that it will be backed by the original eventTimestampHolder map, and any changes to that will be reflected in the returned tail map.
Related
Is there a way to efficiently remove entries from a HashMap which values are in a specified range.
I have following HashMap
private Map<String, Long> accessTimes = new HashMap<>();
I would like to remove all entries where values are between 0 and 200.
Is it possible without iterating through them HashMap? Thank you for any tips.
No you can't do that without iterating over all keys in the map.
In a HashMap, entries are stored in buckets based on the hash code of the entry's key. Therefore, entries are not sorted which forces you to visit all elements to determine if one needs to be removed.
I want a limited size map with some duplicated keys. When size is reached I want delete the oldest entry.
for example, this data set:
MAX_SIZE=5;
map.put(100,"OLDEST");
map.put(101,"XXXX");
map.put(101,"YYYY");
map.put(102,"ZZZZ");
map.put(103,"GGGG");
Then I want to insert a new entry in the map
myLength = map.size()
if(myLength>=MAX_SIZE){
map.remove(the OLDEST)
}
map.put(105,"NEW")
I was thinking in guava multimap, but how delete the oldest entry in multimap?
They KEY is a Long, maybe I need do a for? (not efficient)
oldest=MAX_LONG
for(Long key:map){
if(key<oldest){
oldest=key
}
}
map.remove(oldest)
Use a LinkedListMultimap: it preserves the insertion order, so removing the oldest entry is just a matter of removing the first element of the list returned by entries()
I have a parameter map incoming from a post in a web form. The problem I have is that I want to have the key values sorted.
I have two keys incoming j_idt40:j_idt41:0:score and j_idt40:j_idt41:0:scoreID These I would either want to find without resorting to loop through the map for every row I iterate again. Is there a better way to do this?
j_idt40:j_idt69 = Uppdatera
j_idt40:j_idt41:3:score = 200
j_idt40:j_idt41:0:scoreID = 1
j_idt40:j_idt41:4:scoreID =
j_idt40:j_idt41:3:scoreID = 4
j_idt40:j_idt41:2:scoreID = 3
j_idt40:j_idt41:0:score = 203
j_idt40:j_idt41:2:score = 200
j_idt40:j_idt41:1:score = 200
j_idt40 = j_idt40
j_idt40:j_idt41:4:score = 800
j_idt40:j_idt41:1:scoreID = 2
Natural sorting you need to write your own comparator. The existing comparators in jdk will fail on the following scenario.
TreeMap<String,String> treeMap = new TreeMap<String, String>();
treeMap.put("key1", "value");
treeMap.put("key2", "value");
treeMap.put("key20", "value");
treeMap.put("key10", "value");
treeMap.put("key11", "value");
treeMap.put("key21", "value");
The sorting will happen like this.
key1,key10,key11,key2,key20,key21
Natural sorting is implemented in Java 8 see here
or
Use apache commons ComparatorUtils.NATURAL_COMPARATOR
will TreeMap help you in this regard ?
TreeMap Keeps everything sorted. This is built-in class in Java collection API.
You can use this constructor to convert your map to sorted map.
TreeMap(Map m) // this is from 'java.util.TreeMap'
You can pull all the Map.Entries out into a list, sort that, then loop through it once. You've have to make a Comparitor for Map.Entries.
You can sort the keys like this:
Collection<?> keys = params.keySet();
String[] array = keys.toArray(new String[keys.size()]);
Arrays.sort(array);
Or if you want the entries of the map to be ordered, you can achieve this by inserting them into a TreeMap. When you iterate the TreeMap's key set they come out in order.
Which approach is more "efficient" depends on what measure of efficiency you are talking about (CPU, memory, developer time).
It also depends on how often various things are performed by your application. For example:
lookup, insert and delete operations are on average O(1) for a HashMap and O(logN) for a TreeMap
iterating a TreeMap's key set is O(N)
extracting and sorting a Hashmap's keys is O(NlogN)
Below is a piece of code which I use for inserting the values in a hashmap.
String[] folders={"Movies/HD/By Genre/Action","Movies/HD/By Genre/Comedy"};
HashMap<String, String> sdsResults = new HashMap<String, String>();
for(int i=0; i<folders.length; i++){
sdsResults.put(folders[i], null);
}
Iterator<String> itr = sdsResults.keySet().iterator();
while(itr.hasNext()){
System.out.println("keys in map are = "+itr.next());
}
The output is -
keys in map are = Movies/HD/By Genre/Comedy
keys in map are = Movies/HD/By Genre/Action
Now I wanted to keys to come in the same order as how I had put in. i.e. first the Action one should come and then the Comedy. But reverse order is coming.
Can someone explain why is it so? And I want the order to be the same as the folder contents. How can I achieve this?
The order of keys in a hash is not defined. You want a map. Here's a comparison of the internals.
Basically, when you put something in a hash, you scramble the key. This is a one-way function. The whole point is that you can't un-do it -- it's a way of putting 100 things in 10 boxes.
LinkedHashMap should solve the problem of ordering.
Similar question and the answer here Order of values retrieved from a HashMap
You can use ListOrderedMap from Apache's Commons-Collection library to keep the order.
HashMap selections = new HashMap<Integer, Float>();
How can i get the Integer key of the 3rd smaller value of Float in all HashMap?
Edit
im using the HashMap for this
for (InflatedRunner runner : prices.getRunners()) {
for (InflatedMarketPrices.InflatedPrice price : runner.getLayPrices()) {
if (price.getDepth() == 1) {
selections.put(new Integer(runner.getSelectionId()), new Float(price.getPrice()));
}
}
}
i need the runner of the 3rd smaller price with depth 1
maybe i should implement this in another way?
Michael Mrozek nails it with his question if you're using HashMap right: this is highly atypical scenario for HashMap. That said, you can do something like this:
get the Set<Map.Entry<K,V>> from the HashMap<K,V>.entrySet().
addAll to List<Map.Entry<K,V>>
Collections.sort the list with a custom Comparator<Map.Entry<K,V>> that sorts based on V.
If you just need the 3rd Map.Entry<K,V> only, then a O(N) selection algorithm may suffice.
//after edit
It looks like selection should really be a SortedMap<Float, InflatedRunner>. You should look at java.util.TreeMap.
Here's an example of how TreeMap can be used to get the 3rd lowest key:
TreeMap<Integer,String> map = new TreeMap<Integer,String>();
map.put(33, "Three");
map.put(44, "Four");
map.put(11, "One");
map.put(22, "Two");
int thirdKey = map.higherKey(map.higherKey(map.firstKey()));
System.out.println(thirdKey); // prints "33"
Also note how I take advantage of Java's auto-boxing/unboxing feature between int and Integer. I noticed that you used new Integer and new Float in your original code; this is unnecessary.
//another edit
It should be noted that if you have multiple InflatedRunner with the same price, only one will be kept. If this is a problem, and you want to keep all runners, then you can do one of a few things:
If you really need a multi-map (one key can map to multiple values), then you can:
have TreeMap<Float,Set<InflatedRunner>>
Use MultiMap from Google Collections
If you don't need the map functionality, then just have a List<RunnerPricePair> (sorry, I'm not familiar with the domain to name it appropriately), where RunnerPricePair implements Comparable<RunnerPricePair> that compares on prices. You can just add all the pairs to the list, then either:
Collections.sort the list and get the 3rd pair
Use O(N) selection algorithm
Are you sure you're using hashmaps right? They're used to quickly lookup a value given a key; it's highly unusual to sort the values and then try to find a corresponding key. If anything, you should be mapping the float to the int, so you could at least sort the float keys and get the integer value of the third smallest that way
You have to do it in steps:
Get the Collection<V> of values from the Map
Sort the values
Choose the index of the nth smallest
Think about how you want to handle ties.
You could do it with the google collections BiMap, assuming that the Floats are unique.
If you regularly need to get the key of the nth item, consider:
using a TreeMap, which efficiently keeps keys in sorted order
then using a double map (i.e. one TreeMap mapping integer > float, the other mapping float > integer)
You have to weigh up the inelegance and potential risk of bugs from needing to maintain two maps with the scalability benefit of having a structure that efficiently keeps the keys in order.
You may need to think about two keys mapping to the same float...
P.S. Forgot to mention: if this is an occasional function, and you just need to find the nth largest item of a large number of items, you could consider implementing a selection algorithm (effectively, you do a sort, but don't actually bother sorting subparts of the list that you realise you don't need to sort because their order makes no difference to the position of the item you're looking for).