How to sum up values in a HashMap<String, <String,Integer>>? - java

I have a following HashMap:
HashMap<String, HashMap<String,Integer>> dataArray = new HashMap<>();
In the program, I do use enhanced loop to iterate few times and insert data into the HashMap, based on some kind of key, as in:
dataArray.get(primaryKey).put(length, totalCost)
It produces the following output:
{123-456-789={00:05:00=500, 00:01:06=220}, 999-090-090={00:08:01=900}}
I use a formula to calculate the totalCost value, but I have to make sure it is set to 0 at each iteration's beginning.
My question is, I want to sum up totalCost and length values for each primaryKey. The end result should be something like this:
{123-456-789={00:06:06=720}, 999-090-090={00:08:01=900}}
How would I accomplish that? Do I have to create another HashMap, or is it possible to modify the ones already existing? With a loop perhaps?
EDIT: Forgot to mention that if I try to obtain existing totalCost value with dataArray.get(primaryKey).get(totalCost), compiler complains about a suspicious call to java.util.Map and returns null.

Why so complicated? Just alter your data-structure. OOP is meant to solve precisely that problem. Just store the subtables in an Object each and provide appropriate methods/variables. As for inserting the data into the existing Map: How would you distinguish the resulting sums from what you inserted as standard-values? In addition this would quite likely cause a concurrent modification, though there are ways to work around that.

If you want a an end result in following form :
{123-456-789={00:06:06=720}, 999-090-090={00:08:01=900}}
Why not change your loop to something like this by maintaining only one key-value pair in the map:
Map.Entry<String,Integer> entry=dataArray.get(primaryKey).entrySet().iterator().next();
String key= entry.getKey();
dataArray.get(primaryKey).put(key + length, dataArray.get(primaryKey).get(key) + totalCost);
I hope this helps!

Related

Storing an Array in a HashMap as its value

I want to store a Float array as a value of the HashMap.
HashMap<Integer, Float[]> vFeatureHm = new HashMap<Integer, Float[]>();
The float array here contains a specified number of values, for example say 10. How and where do I mention that ? I will be dynamically adding the values into that array. I can use an ArrayList but I'm using this for a matrix kind structure and it is easy for me to just get the value from the index as the values are stored in that order. ArrayList seems to be an overkill in this case for me. Can you suggest how to solve this. For now, I started working with ArrayList, but I want to know if there is a way to use as I mentioned above.
Update: I realized ArrayList will not work for me in my case as I need to place in a particular index. So I have to use either the format mentioned above or use a HashMap which is again a over kill. Any suggestions on using Float as above mentioned ?
You do not need to specify the dimensions of the Float[] array.
That array is an Object like any other value of the vFeatureHm map, so any bounds checking is irrelevant to the HashMap (although of course it can be performed at another part of your code).
Since float is an object, I initialized it like below.
Float[] featureValues = uFeatureHm.get(userid);
if(featureValues == null){
featureValues = new Float[Settings.noOfCommonFeatures];
featureValues[fi-1] = fv;
uFeatureHm.put(userid, featureValues);
}else{
featureValues[fi-1] = fv;
}
Later, I can simply access a feature of particular user as uFeatureHm.get(userid)[featureIndex]

How to obtain counts of each of the elements of the list?

Given a sorted list of something (a,a,b,c,c)
What would be the most efficient way to recognize that a exists in the list 2 times, b once and c 2 times?
Aside from obvious making a map of counts. Can we do better then this?
if (map.containsKey(key)) {
map.put(key, map.get(key) + 1);
} else {
map.put(key, 1);
}
Ultimately the goal is to iterate of the list and know at any given point how many times a key was seen before. Putting things in a map, seems like a step we don't really need.
I would use a Multiset implementation in Guava - probably a HashMultiset. That avoids having to do a put/get on each iteration - if the item already exists when you add it, it just increments the count. It's a bit like using a HashMap<Foo, AtomicInteger>.
See the Guava User's Guide entry on Multiset for more details.
Your method, at each iteration, makes
one lookup for containsKey
one lookup for get
one unboxing from Integer to int
one boxing from int to Integer
one put
You could simply compare the current element to the previous one, increment a count if it's equal, and put the count if not (and reset the counter to 1).
But even if you keep your algorithm, using get and compare the result to null would at least avoid an unnecessary lookup.

Which datastructure to use?

I have a scenario like this,
I need to store the count of the strings and I need to return the top ten strings which has the max count,
for example,
String Count
---------------------------------
String1 10
String2 9
String3 8
.
.
.
String10 1
I was thinking of using the hashtable for storing the string and its count but it would be difficult to retrieve the top ten strings from it as I have to again loop through it to find them.
Any other suggestions here?
Priority Que.
You can make a class to put in it:
public class StringHolder{
private String string;
private int value;
//Compare to and equals methods
}
then it will sort when you insert and it is easy to get the top 10.
Simply use a sorted map like
Map<Integer, List<String>> strings
where the key is the frequency value and the value the list of strings that occur with that frequency.
Then, loop through the map and, with an inner loop through the value lists until you've seen 10 strings. Those are the 10 most frequent one's.
With the additional requirement that the algorithm should support updates of frequencies: add the strings to a map like Map<String, Integer> where the key is the string and the value the actual frequency (increment the value if you see a string again). After that copy the key/value pairs to the map I suggested above.
For any task like "find N top items" priority queues are perfect solution. See Java's PriorityQueue class.
I am not sure, but i guess that the most suitable and elegant class for your needs is guava's
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/TreeMultiset.html
Guava has a HashMultiset which would be very useful for this.
HashMultiset<String> ms = Hashmultiset.create();
ms.add(astring);
ms.add(astring, times);
ImmutableMultiset<String> ims = Multisets.copyHighestCountFirst(ms);
// iterator through the first 10 elements, and they will be your top 10
// from highest to lowest.
You need a Max Heap data structure for this. Put it all into the max heap, and make successive 10 (or whatever n) removals.
And if you intend to keep reusing the data once it's loaded into memory, it might be worth the expense of sorting by value instead of a heap.

What's the best way to remove duplicate URI params from a string?

I have a string, root?param1=...&param2=...&param3=..., and I want to create a java method that will remove any duplicate params. The values will always be the same, but sometimes the params are duplicated as per the application's function (don't ask). Therefor,
HTTP://root?param1=value&param2=value2&param2=value2param3=value3&param3=value3&param1=value&param1=value
becomes
HTTP://root?param1=value&param2=value2&param3=value3
I've been out of programming too long to remember the best ways to do this but my original train of thought went something like this:
Grab each param and stick into a temp array, run through temp array and compare if array[i] equals to any other param name. If so, delete. If not, add back to a return string. At end of loop, print return string.
But that would require O(n) for the length of the URI plus O(m)! for the size of the array (m being the number of params). I think that would be pretty bad considering I'll be running this method around 5,000x per minute for all incoming URIs. Is there a better way to go about this or an out-of-the-box java method that handles some of the overhead?
You could stick the key/value pairs into a Map<String,String>. That'll automatically take care of duplicated keys, and will be very easy to code up.
To verify that parameters with identical keys have identical values, you could check the return value of put(): it should be either null, or equal to the value you've just inserted.
If you insist on doing this (don't?), then you could use a Map.
For each of your parameter - value pairs, insert them into the map.
You'll be left with only unique parameters, which you can then use to rebuild your URI.
You'd be iterating your parameter - value pairs once, then iterating your Map once to rebuild the URI.
Or, like Thilo said, you could not do this and let the receiver deal with the duplicates.
For the love of God, don't write your own crufty parser for this.
Find an HTTP library which handles parameter parsing and use that.
This might do the trick: http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/client/utils/URLEncodedUtils.html
Here's my solution with lambda expression in Java.
// input: query string
// output: parameter map(Map<String, String>) in least recently updated order
List<String> pairs = Splitter.on("&").splitToList(queryStr);
return pairs.stream().map(s -> s.split("=", 2)).collect(Collectors.toMap(pair -> pair[0],
pair -> (pair.length > 1 ? pair[1] : ""), (formerValue, latterValue) -> latterValue, LinkedHashMap::new));

nth item of hashmap

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

Categories

Resources