I usually come across scenarios while using HashMap in Java as follows :
I've a list of Objects of class A (List<A>)
A has fields int f1, int f2 and other fields.
I've to construct a map from List to perform O(1) lookup for the Objects of A. The key is combination of f1 and f2 (both being integers).
Now which of the following would be the best practice to use for the map
case 1 : in general
case 2 : f2 can take only 2 to 3 different values, while f1 can take large number of values.
Map<Integer, Map<Integer, List<A>>> // construction of map is cumbersome
Map<String, List<A>> //(key : String f1 + "_" + f2)
Map<Integer, List<A>> //(I tend to use this for case 2)
Missed to clarify one thing here. f1 and f2 don't uniquely identify objects of A. Corrected the map definitions.
If those two fields tend to be immutable (they don't change once set), you can override the equals() and hashCode() methods of A, and simply store a:
Set<A> //(key: fields f1 and f2, via hashCode() method)
If they are not immutable, you cannot use them for the key anyway, since they might change.
I think Map is suitable for case 1, and for case, i recommend List, and this list only have 2-3 elements, then you can map an index to the specific field value.
Why use a map at all? If you don't really need Key-Value pairs, you can just use a HashSet<A>. The lookup is still O(1) and you don't have to bother getting a value from the key.
Of course, the HashSet is probably just a HashMap with null values, but you don't have to invent keys and values.
I don't like using Strings as composite keys. Some blogger out there put it well: Strings are good for things that are text, and not good for things that aren't text.
Why not just create a simple IntPair class with two int fields, and appropriate hashCode() and equals(Object) overrides? It'll take you two seconds in an IDE (not much longer without one), and you'll have a more specific, semantically meaningful key type.
Key is unique in HashMap...because internally in java key is set as
final Key
int static Entry class in java
That's why the key is unique it won't allow duplicates...
Related
I want an indexed collection in Java, but my final Object needs to be indexed by many keys.
I have now a collection of this kind:
Map<String, Map<String, Map<String, Map<String, Map<String, Object>>>>> objects
I am asking if this is efficent or it is better to build a more complex key Type to include all of the 5 string keys.
PS:
Sorry i didn't explain the whole thing.
When i try to get an object with this collection the path to this object might be: (call AX the generic key in 1-st position, BX the generic key in 2-th position, etc...)
A1 -> B1 -> C1 -> D1 -> E1. But it can be also A1 -> B2 -> C1 -> D1 -> E1.
So i am asking if a complex key that overrides equals to match B2 and B1 as one and match the two described paths it's more efficent than have a nested Map.
If you don’t need a tree structure and you always want to find one stored object. I would suggest to have a compound key. You can concatenate Strings with delimiter as a key.
For two dimensions Table from Guava can be used: https://github.com/google/guava/wiki/NewCollectionTypesExplained#table
It depends on what you need it for. Will you only access the most nested objects, one at the time, or some of the outer maps as well. As an example: Lets assume that objects are houses and the map keys are different parts of the address. First one is country, then city, then street, then house number.
If you want to be able to get all houses in city X you problably want to use nested maps like in your example. With complex Address class as a key it won't be really possible.
If you don't need that functionality and you will always use all parts then a composite class will be more convenient
Edit:
After your edit it seems that a composite class will be a better option. Calling a constructor with meaningful parameter names (as some IDEs show those) will be much nicer than chaining 5 times .get(String).
I want to get all the values(multiple) of a particular key.But i m getting only one value?I dont know how to print all the values.Great help if someone correct the code..did not get any help from google search..
import java.util.*;
public class hashing
{
public static void main(String args[])
{
String[] ary=new String[4];
String key;
char[] chrary;
ary[0]=new String("abcdef");
ary[1]=new String("defabc");
ary[2]=new String("ghijkl");
ary[3]=new String("jklghi");
Hashtable<String, String> hasht = new Hashtable<String, String>();
for(int i=0;i<4;i++){
chrary=ary[i].toCharArray();
Arrays.sort(chrary);
key=new String(chrary);
hasht.put(key,ary[i]);
}
Enumeration iterator = hasht.elements();
while(iterator.hasMoreElements()) {
String temp = (String)iterator.nextElement();
System.out.println(temp);
}
}
}
PS:output is defabc jklghi.I want abcdef defabc ghijkl jklghi.
Hashtables can only contain one value per key. To store multiple values, you should either
Store a collection (e.g. List<String> or array) per key. Note that you'll have to initialise the collection prior to insertion of the first value corresponding to that key
Use a MultiMap
Note that many MultiMap implementations exist. The Oracle docs provide a simple implementation too (see here, and search for MultiMap)
The way HashMaps work is that there is only one value for a given key. So if you call:
map.put(key, value1);
map.put(key, value2);
the second line will override the value corresponding to the key.
Regarding your comment about collision, it means something different. Internally, a HashMap stores the key/value pairs in buckets that are defined based on the hashcode of the key (hence the name: hashmap). In the (low probability if the hashcode function is good) case where two non-equal keys have the same hashcode, the implementation needs to make sure that querying the hashmap on one of those keys will return the correct value. That is where hash collision need to be handled.
That's not what collision resolution is meant to do. Collision resolution lets you handle the case when two object with different keys would go into the same "bucket" in the hash map. How this resolution happens is an internal detail of the hash map implementation, not something that would be exposed to you.
Actually, in your case, its not collision, its same key with same hashcode. In general Collision occurs only if two different keys generate same hashcode, This can occur due to a bad implementation of hashCode() method.
Yes, java.util.HashMap will handle hash collisions, If you look at the source code of HashMap, it stores each value in a LinkedList. That means, if two different keys with same hashcode comes in.. then both values will go into same bucket but as two different nodes in the linked list.
Found this link online, which explain How hash map works in detail.
if key is the same, the value will be updated. jvm will not put a new key/value for same keys...
Your Hashtable<String, String> maps one string to one string. So put replaces the value that was before linked to a specific key.
If you want multiple values, you can make a Hashtable<String, []String> or a Hashtable<String, List<String>>.
A cleaner solution would be to use Google's Multimap which allows to associate multiple values to one key :
A collection similar to a Map, but which may associate multiple values
with a single key. If you call put(K, V) twice, with the same key but
different values, the multimap contains mappings from the key to both
values.
You are only putting one String for each key:
hasht.put(key,ary[i]);
So if i=1 that means you put defabc, why do you expect to get multiple values for same key?
Hashtable, like all Map keep only one value per key, the last value you set.
If you want to keep all the values, just print the original array.
String[] ary = "abcdef,defabc,ghijkl,jklghi".split(",");
System.out.println(Arrays.toString(ary));
prints
[abcdef, defabc, ghijkl, jklghi]
I have an Android app in which I use a HashMap to store container objects. During the course of the App, the datastructure is accessed continuously.
However, about half the time, the reference used in not the Key in the map but another variable from the object so I end up looping over the structure again and again.
Is there an efficient way to have a datastructure indexed on two keys in Java ?
Why not two maps with different keys, but that both refer to the same values?
Manage two maps, where two sets of keys map to the same underlying set of objects. Wrap them in a class that has methods similar to a normal map, but internally searches on both keys, and synchronizes additions and deletions.
This is efficient because manipulations are (in the worst case) linearly proportionate to managing a single map.
I'd create a key object that combines the two variables.
You could use one map with both keys:
Map<Object, Person> personMap = new HashMap<Object, Person>()
Person person = ...
personMap.put(person.getName(), person)
personMap.put(person.getSSN(), person)
Then you can retrieve by the key. This of course assumes that there are no collisions in your key usage. If your two keys are different class types, then this is safe to do. If your keys are the same type (example String), then you may not want to use the two maps solution.
Follow-up: This approach does suffer from losing type safety, but it only impacts put(K, V) and putAll(Map<? extends K, ? extends V>), as get(Object) and containsKey(Object) always accepts Object.
So with this limitation I'd wrap this single map or go with the two map solution (also wrapped).
I am looking for an appropriate data structure for my problem. I would like to be able to select node objects as efficiently as possible using two keys. Insertion and deletion also needs to be efficient. Basically every node object has a pair of two keys. The pairs are unique but the individual keys are not. I need to be able to select a group of nodes that have a particular value for one of the two keys.
Example:
Node1 has keys a1 and b1
Node2 has keys a1 and b2
Node3 has keys a2 and b2
I would like to for example be able to select the node with the key a1,b1 but also all nodes that have b2 as key2.
I could of course make two HashMaps (one for each key) but this is kind of an ugly solution because when I add or remove something I would have to do it in both maps. Since there will be a lot of adding and removing going on I would prefer to do this in one go. Does anyone have any ideas about how to do this?
Obviously having a single key that merges the two keys together does not solve the problem because I also need to be able to search for a single key without having to search through the whole map. That wouldn't be very efficient. The problem is an efficiency problem. I could just search every entry in the map for a particular key but instead I would like to use a hash so that I can select multiple node objects using either one of the two keys instantly.
I am not looking for something like the MultiKeyMap because in this data-structure the first key always stays the same, you can only add keys instead of replacing the first key with a different key. I want to be able to switch between the first and the second key.
I do and do not want to store multiple objects with the same key. If you look at the example you can see that the two keys together are always unique. This can be seen as a single key therefore I would not store multiple objects under the same key. But if you look at the individual keys, these are not unique therefore I do want to store multiple objects referenced by the individual keys.
If you can use a library, take a look at the Table interface of Guava. It associates a row and a column with a value. The row and columns may be your first and second keys. Also you can have searches by row or by column.
One of the implementations of this interface is hash based.
You have to create a key class (equality is treated as Point):
public class Key {
int field1;
int field2;
public boolean equals(Object o) {
if (o == null || !(o instanceof Key)) return false;
Key other = (Key) o;
return field1 == other.field1 && field2 == other.field2;
}
public int hashCode() {
return field1*field2; // doesn't matter if some keys have same hash code
}
}
For selecting keys with one specific value in the first field:
public List<Key> getKeysWithField1EqualsTo(int value) {
List<Key> result = new ArrayList<>();
for (Key k: map.keySet()) {
if (k.field1 == value) result.add(k);
}
return result;
}
Since this is rather specific to your problem at hand, you will very likely need to develop your own collection. I would wrap two MultiMaps from Apache Commons into my own collection class that deals with updates of both multi-maps at the same time, and use my class to perform inserts and queries.
Write a simple class that is able to contain two values (the keys) and override equals(..) and hashCode() for equality checks used by the map. Use this simple class as the key for the map.
Here you can find a hashmap compatible pair class (2nd answer):
What is the equivalent of the C++ Pair<L,R> in Java?
Since a HashMap can only sort on one hash for every object, you will never be able to select the distinct lists 'out of the box'. What I would suggest is using a Tuple with two keys, and then iterate over the HashMap and select only those elements that have tuple.key1=X.
HashMaps can have any object as Key so why not create a class with 2 fields and consider this class as your key. you can also Override the Equals method to tell it how the keys are equals
I think we can do it in this way: For each key, we can compute the corresponding hashcode.
key1 -> hashcode1
key2 -> hashcode2
Then we have a 2-d array, with N columns and N rows.
key1 -> rowIndex: hashcode1 MOD N
key2 -> columnIndex: hashcode2 MOD N
Then we store the item in array[rowIndex][columnIndex].
In this implementation, you can get all the entries with a target key1, and any key2. You can also get all the entries with a target key2, and any key1.
This array may expand when there are a lot of collisions, just like what you do with the ordinary hashmap.
hi
I want to create a HashMap (java) that stores Expression, a little object i've created.
How do I choose what type of key to use? What's the difference for me between integer and String? I guess i just don't fully understand the idea behind HashMap so i'm not sure what keys to use.
Thanks!
Java HashMap relies on two things:
the hashCode() method, which returns an integer that is generated from the key and used inside the map
the equals(..) method, which should be consistent to the hash calculated, this means that if two keys has the same hashcode than it is desiderable that they are the same element.
The specific requirements, taken from Java API doc are the following:
Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.
If you don't provide any kind of specific implementation, then the memory reference of the object is used as the hashcode. This is usually good in most situations but if you have for example:
Expression e1 = new Expression(2,4,PLUS);
Expression e2 = new Expression(2,4,PLUS);
(I don't actually know what you need to place inside your hashmap so I'm just guessing)
Then, since they are two different object although with same parameters, they will have different hashcodes. This could be or not be a problem for your specific situation.
In case it isn't just use the hasmap without caring about these details, if it is you will need to provide a better way to compute the hashcode and equality of your Expression class.
You could do it in a recursive way (by computing the hashcode as a result of the hashcodes of children) or in a naive way (maybe computing the hashcode over a toString() representation).
Finally, if you are planning to use just simple types as keys (like you said integers or strings) just don't worry, there's no difference. In both cases two different items will have the same hashcode. Some examples:
assert(new String("hello").hashCode() == new String("hello").hashCode());
int x = 123;
assert(new Integer(x).hashCode() == new Integer(123).hashCode());
Mind that the example with strings is not true in general, like I explained you before, it is just because the hashcode method of strings computes the value according to the content of the string itself.
The key is what you use to identify objects. You might have a situation where you want to identify numbers by their name.
Map<String,Integer> numbersByName = new HashMap<String,Integer>();
numbersByName.put("one",Integer.valueOf(1));
numbersByName.put("two",Integer.valueOf(2));
numbersByName.put("three",Integer.valueOf(3));
... etc
Then later you can get them out by doing
Integer three = numbersByName.get("three");
Or you might have a need to go the other way. If you know you're going to have integer values, and want the names, you can map integers to strings
Map<String,Integer> numbersByValue = new HashMap<String,Integer>();
numbersByValue.put(Integer.valueOf(1),"one");
numbersByValue.put(Integer.valueOf(2),"two");
numbersByValue.put(Integer.valueOf(3),"three");
... etc
And get it out
String three = numbersByValue.get(Integer.valueOf(3));
Keys and their associated values are both objects. When you get something from a HashMap, you have to cast it to the actual type of object it represents (we can do this because all objects in Java inherit the Object class). So, if your keys are strings and your values are Integers, you would do something like:
Integer myValue = (Integer)myMap.get("myKey");
However, you can use Java generics to tell the compiler that you're only going to be using Strings and Integers:
HashMap<String,Integer> myMap = new HashMap<String,Integer>();
See http://download.oracle.com/javase/1.4.2/docs/api/java/util/HashMap.html for more details on HashMap.
If you do not want to look up the expressions, why do you want them to store in a map?
But if you want to, then the key is that item you use for lookup.