I've been searching StackOverflow for an answer regarding this issue.
Lets say I created two array lists,
arraylist1 holds Strings
arraylist2 holds Integers.
NOTE - I've added things into both of these arraylists. The values at each of the indices are related to the other value.
Meaning. lets say index 1 of arraylist1 = "Name". Index 1 of arraylist2 = 3, they are related in that I want to put things into a TreeMap (for the purpose of sorting by key) so that the treemap puts in the value ("Name", 3).
My problem -
TreeMap<String, Integer> mymap = new TreeMap<String, Integer>();
for(String s : arraylist1) {
for(Integer v : arraylist2) {
mymap.put(s, v);
The problem with this is if I added a bunch of random things for testing,
arraylist1.add("h");
arraylist1.add("i");
arraylist1.add("e");
arraylist2.add(1);
arraylist2.add(3);
arraylist2.add(2);
And I did the for loops, my result would come out to...
Key e Value: 2
Key h Value: 2
Key i Value: 2
Which solves the problem of sorting by key. However, the problem is that only the last value in the Integer arraylist, arraylist2, is being put into the TreeMap.
Don't you want to iterate through both lists at the same time ?
for (int i = 0; i < list.size(); i++) {
map.put(list1.get(i), list2.get(i));
}
As it currently stands, you're iterating over your second map for each key, and inserting the second list's values. Since a map only holds one value per key, your map results in the final value in your second list for each key.
As an aside, if these 2 values are intrinsically linked, perhaps create (or use an existing) Pair object to store these from the outset. The problem with using a standard map is that you can only store one value per key. e.g. you can't store (A,B) and (A,C)
Well fark, I was typing this in your deleted question before you deleted it, but didn't finish til after you deleted it:
I'm not sure if I fully understand your question, but consider:
Creating a Game class that is in charge of the logic of the game.
Creating Player objects that interact with the Game.
When a Player wants to move, he calls Game's move(Piece piece, Position position) method, but with parameters.
Have this method return a boolean, true if the move is valid and false if not...
Related
I am currently preparing for interviews, Java in particular.
A common question is to explain hash maps.
Every explanation says that in case there is more than a single value per key, the values are being linked listed to the bucket.
Now, in HashMap class, when we use put(), and the key is already in the map, the value is not being linked to the existing one (at list as I understand) but replacing it:
Map<String, Integer> map = new HashMap();
map.put("a", 1);
//map now have the pair ["a", 1]
map.put("a", 2);
//map now have the pair ["a", 2]
//And according to all hash maps tutorials, it should have been like: ["a", 1->2]
From the docs:
If the map previously contained a mapping for the key, the old value
is replaced.
What am I missing here? I am a little confused...
Thanks
You're confusing the behaviour of a Map with the implementation of a HashMap.
In a Map, there is only one value for a key -- if you put a new value for the same key, the old value will be replaced.
HashMaps are implemented using 'buckets' -- an array of cells of finite size, indexed by the hashCode of the key.
It's possible for two different keys to hash to the same bucket, a 'hash collision'. In case of a collision, one solution is to put the (key, value) pairs into a list, which is searched when getting a value from that bucket. This list is part of the internal implementation of the HashMap and is not visible to the user of the HashMap.
This is probably what you are thinking of.
Your basic understanding is correct: maps in general and hashmaps in particular only support one value per key. That value could be a list but that's something different. put("a", 2) will replace any value for key "a" that's already in the list.
So what are you missing?
Every explanation says that in case there is more than a single value per key, the values are being linked listed to the bucket.
Yes, that's basically the case (unless the list is replaced by a tree for efficiency reasons but let's ignore that here).
This is not about putting values for the same key into a list, however, but for the same bucket. Since keys could be mapped to the same bucket due to their hash code you'd need to handle that "collision".
Example:
Key "A" has a hash code of 65, key "P" has a hash code of 81 (assuming hashCode() just returns the ascii codes).
Let's assume our hashmap currently has 16 buckets. So when I put "A" into the map, which bucket does it go to? We calculate bucketIndex = hashCode % numBuckets (so 65 % 16) and we get the index 1 for the 2nd bucket.
Now we want to put "P" into the map. bucketIndex = hashCode % numBuckets also yields 1 (81 % 16) so the value for a different key goes to the same bucket at index 1.
To solve that a simple implementation is to use a linked list, i.e. the entry for "A" points to the next entry for "P" in the same bucket.
Any get("P") will then look for the bucket index first using the same calculation, so it gets 1. Then it iterates the list and calls equals() on each entry's key until it hits the one that matches (or none if none match).
in case there is more than a single value per key, the values are being linked listed to the bucket.
Maybe you mistake that with: Multiple keys can have the same hashCode value. (Collision)
For example let's consider 2 keys(key1, key2). Key1 references value1 and Key2 references value2.
If
hashcode(key1) = 1
hashcode(key2) = 1
The objects might have the same hashCode, but at the same time not be equal (a collision). In that situation both values will be put as List according to hashCode. Values will be retrieved by hashCode and than you'll get your value among that values by equals operation.
I have following decision table:
My task is to compare all objects (S1, S2, S3...) with each other using choosen attributes set (e.g {Distance, Capacity}). So to achieve this I have to create two LOOPS (one nested) and use IF condition.
When objects set is small everything is working fine. But when set is big (e.g 10000 objects) performance of this solution is getting worse...
Is it another, faster, "smarter" way do do it?
Pseudocode:
Step 1. HashMap<String, ArrayList<String>> hashMap = new HashMap<>();
Step 2. For each object s do
String key = getSelectedAttributesValueInString();
if (!hashMap.containsKey(key)) {
hashMap.put(key, new ArrayList<String>());
}
hashMap.get(key).add(s.getName);
Here getSelectedAttributesValueInString is the concatenation of all the Selected Attributes Value.
For example: object s1 Attributes {Distance, Capacity} the function return ShortYES.
Step 3. Now print the hashMap arraylist value that have length greater than 1.
Complexity Analysis:
Your approach O(n^2)
My Approach O(n) (Because HashMap add and get complexity is O(1))
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.
I have a text file like the format below
module1.q1=a1
module1.q2=a2
module2.q1=a1
module2.q5=a6
..
..
I have a class objectsHmp which has two String variables to store questions(q1, q2, q3,...) and answers(a1,a2,a3,..). what i'm trying to do is keeping the module id as the key, i want to populate a hashmap with values as arraylist of objects(of objectsHmp). And in turn i'm storing the keys in an arraylist of String.
In the below code snippet,
*l_ext_keys* is an arraylist of String which stores the keys,
*l_extract* is a HashMap>,
*l_temp_array* is an arraylist of object objectsHmp,
while((line=br.readLine()) != null)
{
String[] ss = new String[2];
ss = line.split("=");
String tss = ss[0];
String[] kss = tss.split("\\.");
objectsHmp temp = new objectsHmp(kss[1],ss[1]);
if(!prev.equals(kss[0]))
{
l_ext_keys.add(prev);
l_extract.put(prev,l_temp_array);
l_temp_array.clear();
}
l_temp_array.add(temp);
prev = kss[0];
}
l_extract.put(prev,l_temp_array);
l_ext_keys.add(prev);
l_temp_array.clear();
Problems
The Hashmap is getting populated but it's not having values for some keys present in the l_ext_keys. I tried printing the length of the arraylist and hasmap, but its having a great difference(arraylist with the keys having more values than hashmap).
One possible reason for this difference is some module is repeated.
I dint override any function
Question
What are the possibilities that hashmap couldn't get values for the keys present in the list? Or am I doing some big mistake here?
Its not possible to have a key more than once in a HashMap. Keys must be unique. So you override the old key with your approach right now.
You could use the HashMap as a directory, saving all values for one key in an Array or ArrayList and then define:
HashMap<String, ArrayList<String>> directory = new HashMap<String, ArrayList<String>>();
After that you can retrieve an ArrayList holding the values for q1 with the key q1
EDIT:
Your code is missing some information, but as far as I can see you are putting module1 and so on as the key in your hashmap. You check through if(!prev.equals..) for a new module, but that means only the first occurence of some module is being stored (if your file is sorted). If the list is not sorted, its getting overriden somewhere in the process.
Your whole function seems a bit buggy. :) Also check the code where you work with the temp arrayList, because you always add the question and answer to it. So some questions&answers get even saved with the wrong module. And at the first run of the while loop l_temp_array seems to be empty, so you add module1 with an empty value to the HashMap..
The problem with your code is that it doesn't handle well cases when the module names are not sorted, e.g.
module1.q1=a1
module2.q1=a1
module1.q2=a2
module2.q5=a6
You can add values directly to the hashmap without using temporary lists, like this:
objectsHmp temp = new objectsHmp(kss[1],ss[1]);
ArrayList<objectsHmp> list = l_extract.get(kss[0]);
if(list == null){
list = new ArrayList<objectsHmp>();
l_extract.put(kss[0], list);
}
list.add(temp);
This solution will remove the risks I mentioned in the beginning.
Also, you're not following 100% the Java notation conventions, e.g. method names should have capital first letter; and for variable names the camelCase notation is preferred rather than underscores.
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).