HashMap overrides the nextvalue Java - java

Lets say I have hashmap store and it contains for example-(11,name1) (11,name2) and i call HashMap.get(11), it only shows name2 which means it overrides the first input for 11. How can i store both name1 and name2 with ID 11 using hashmap?I know i can use both HashMap and HashSet but i dont want to create every HashSet for HashMap. I just want to use hashSet only. how should I do this? I hope you can help me with it. Thank you.
public void insert(int ID, String key){
int hashKey = Hash(key);
System.out.println("Hash Key" + hashKey);
int node = Find(ID,hashKey);
storeR.put(node, key);
}

You can use:
HashMap<Integer, List<String>>
In HashMap you must put a value with every key. So of course, if you put the same key twice, the value will be override.
The solution is to hold a collection of values for every key.
in your code instead of:
storeR.put(node, key);
you should write:
List<String> nodeValues = storeR.get(node);
if (nodeValues == null) {
nodeValues = new ArrayList<String>();
storeR.put(node, nodeValues );
}
nodeValues.add(key);
And you should also change storeR type to be HashMap<Integer, List<String>>
MultiMap is also a similar solution.

You can probably use MultiMap from Apache Commons Collections.

You will have to either have a HashMap where the value of each key is another collection (list or set) or concatenate the string values together (e.g. comma separated).
Alternatively you may be able to find a data collection that supports multiple values per key.

To store multiple values for a single key, use a HashMap that contains a list as a value. HashMap's implementation overrides values for existing keys.
HashMap<Integer,List<String>>
Also, you could use MultiMap from Apache Commons or, if you're just using Integer I can suggest you use an array directly:
List<String>[] yourList = new List<String>[initCapacity];
So you can access that list like this:
yourList[0].add("A New Value");
As a final note, you can use any collection you deem appropiate, even a HashSet if performance is important for you and you won't store duplicated values for a same index.

Related

How to make a key have multiple values in a Hashtable? [duplicate]

This question already has answers here:
HashMap with multiple values under the same key
(21 answers)
Closed 6 years ago.
I have 100 entries and I have to have to hash these into a hashtable of a limited size.
I know how to work with the first entry, ht.put(k,v) does the trick.
But as soon as I want to add another value to it, the old one gets overwritten. I don't want to do that, I want to append it in a linkedlist or arraylist.
Hashtable<Integer,Integer> ht = new Hashtable<Integer,Integer>(211);
ht.put(1, 40);
ht.put (1, 60);
System.out.println(ht.get(1));
// output is 60
How to make it both 40 and 60?
You can have List as value type like:
Hashtable<Integer,List<Integer>> ht = new Hashtable<Integer,List<Integer>>(211);
And your put operation would look like:
public static void put(Hashtable<Integer,List<Integer>> ht, int key, int value) {
List<Integer> list = ht.get(key);
if (list == null) {
list = new ArrayList<Integer>();
ht.put(key, list);
}
list.add(value);
}
[UPDATE1]
If you want you can make your one extension of Hashtable like:
public class MyHashtable extends Hashtable<Integer,List<Integer>> {
public MyHashtable(...) { // add params if needed
super(...);
}
// with additional method:
public static void putOne(int key, int value) {
List<Integer> list = this.get(key);
if (list == null) {
list = new ArrayList<Integer>();
this.put(key, list);
}
list.add(value);
}
}
You need linear probing http://www.sanfoundry.com/java-program-implement-hash-tables-linear-probing/
It's not possible to store more than one value in a cell of a hash table
When trying to map a new key to an already occupied cell this is called a collision.
There are a few algorithm schemes to try and work around collision, one is Linear probing - which finds the next most appropriate free space for the key to be stored
The data structure you are looking for is called Multi Map. By definition it has different interface than a map, because it allows multiple values associated with the same key.
There's no standard library implementation for this data structure yet. But you can find good ones in some open source libraries:
Guava
Apache Commons Collections
Multimap (https://google.github.io/guava/releases/snapshot/api/docs/com/google/common/collect/Multimap.html) should help if you are allowed to use it.
Alternatively, you could use Map<Integer, List<Integer>>.
You are using same key (1), which is not what you wanted, unless you wanted to add more values to the same key, in that case have hashtable of list of arrays HashMap<Integer,List<Integer>> integerArrayMap.
In Hashtable, the Key MUST be unique, as you are NOT using unique keys, the same value is being replaced. so try to put the values with different keys.
ht.put(1, 40);
ht.put (2, 60);
I suggest you to refer the Hashtable api here:
https://docs.oracle.com/javase/7/docs/api/java/util/Hashtable.html

Looping to enter values into Java Hashmap

i am trying to insert values into a hashmap. I have it in a loop as the values are being retrieved from a list of strings. The code is as follows:
HashMap<String, String> resultHashMap = new HashMap<String, String>();
//add the top document id back to the resultHashMap
resultHashMap.put("entryObject", dsStepParam.getValue());
for(String res : results)
{
log.info(res);
resultHashMap.put("dataObject", res);
}
The hashMap (after this loop should contain the following:
{"entryObject":"500386787",
"dataObject":"500386883;500901929",
"dataObject":"500386906;500901969",
"dataObject":"500386787;500901666",
"dataObject":"500386784;500901654",
"dataObject":"500386762;500901599"}
however the actual contents are:
{"entryObject":"500386787",
"dataObject":"500386762;500901599"}
As you can see it only stores the entryObject and the last dataObject.
How can I make it store all the values in the hashMap?
It only stores the last entry because duplicate keys are not allowed in a hashmap. To store all elements you could do something like this
int count = 0;
for(String res : results)
{
log.info(res);
resultHashMap.put("dataObject-"+count, res);
count++;
}
Thus you'd get something like this
{"entryObject":"500386787",
"dataObject-1":"500386883;500901929",
"dataObject-2":"500386906;500901969",
"dataObject-3":"500386787;500901666",
"dataObject-4":"500386784;500901654",
"dataObject-5":"500386762;500901599"}
If you want it to store all values in the hashMap you need to allow duplicates in the map. For this to happen, you'd need to use Google's version of Multimap, which can be found here
The keys in hashMap are unique so you are seeing the last entry for the duplicate keys inserts. If you want to store multiple items associated to one key then you can make use MultiMap i.e a map that holds a collection of values against each key. Couple of good multimap implementations are available:
Apache MultiMap
Guava MultiMap

How To Access hash maps key when the key is an object

I cannot seem to figure out how to access the values of my hashmap
What I am basically trying to do is create a hashmap with an array as one of the values like json style.. If that makes sense?
So I want something like hash{key: value1, value2, value3, [number1,number2]}
and be able to access it like (pseudocode:) hash.get(3).get(1)
public class WebSearch {
readFile.ReadFile xfile = new readFile.ReadFile("inputgraph.txt");
HashMap webSearchHash = new HashMap();
ArrayList belongsTo = new ArrayList();
ArrayList keyphrase = new ArrayList();
public WebSearch() {
}
public void createGraph()
{
HashMap <Object, ArrayList<Integer> > outlinks = new HashMap <Object, ArrayList<Integer>>();
for (int i = 0; i < xfile.getNumberOfWebpages(); i++ )
{
keyphrase.add(i,xfile.getKeyPhrases(i));
outlinks.put(keyphrase.get(i), xfile.getOutLinks(i));
}
}
keyphrases is an ArrayList
this is my output of System.out.print(outlinks);
{[education, news, internet]=[0, 3], [power, news]=[1, 4], [computer, internet, device, ipod]=[2], [university, education]=[5]}
How would I go about getting say just this: [education, news, internet]=[0, 3]
I have tried:
outlinks.get(xfile.getKeyPhrases(i))
xfile.getKeyPhrases(0) would for example return [education, news, internet]
You can get the key set (Map.keySet()) of the map first; outlinks.keySet()
Then you can use these keys on your map to get your entries (values of the keys)
You haven't posted enough of the surrounding code for your question to be entirely clear, but look at the Javadocs for Map. You will probably get what you want by iterating over outlinks.values().
I recommend to use a customized object and use it inside your collections.
You may create a POJO/Bean class and overwrite the toString method with the details that you want, for instance the a iterate over items inside a array.
When you use it to print or display the toString method will be call.
The following link show you some ideas:
http://www.javapractices.com/topic/TopicAction.do?Id=55
http://en.wikipedia.org/wiki/Plain_Old_Java_Object
You can access the keys of any HashMap using Map.keySet() method.
Also note that java.util.HashMap is unordered. HashMap makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time.
You would like to relook at the structure of your HashMap, you are having ArrayList as your key.

HashMap with ArrayList key can not find it when Arraylist grows

Well my problem is that in some part of my code I use an arraylist as a key in a hashmap for example
ArrayList<Integer> array = new ArrayList<Integer>();
And then I put my array like a key in a hash map (I need it in this way I'm sure of that)
HashMap<ArrayList<Integer>, String> map = new HashMap<ArrayList<Integer>, String>();
map.put(array, "value1");
Here comes the problem: When I add some value to my array and then I try to recover the data using the same array then the hash map cant find it.
array.add(23);
String value = map.get(array);
At this time value is null instead of string "value1"
I was testing and I discovered that the hashCode changes when array list grows up and this is the central point of my problem, but I want to know how can I fix this.
Use an IdentityHashMap. Then that same array instance will always map to the same value, no matter how its contents (and therefore hash code) are changed.
You can't use a mutable object (that is, one whose hashCode changes) as the key of a HashMap. See if you can find something else to use as the key instead. It's somewhat unusual to map a collection to a string; the other way around is much more common.
Its a weird use case but if you must do it then you can sub class the array and override the hashCode method.
Its a bit of an add thing to try and do in my opinion.
I assume what you are trying to model is a variable length key made up of n integers, and assume that the hash of the ArrayList will be consistent, but I'm not sure that is the case.
I would suggest that you either subclass ArrayList and override the hash() & equals() methods, or wrap the HashMap in a key class.
I'm almost certain you would not want to do that. It's more likely you would want a Map<String, List<Integer>>. However, if you absolutely must do this, use a holder class:
public class ListHolder {
private List<Integer> list = new ArrayList<Integer>();
public List<Integer> getList() {return list;}
}
Map<ListHolder, String> map = new HashMap<ListHolder, String>;
The basic reason: When we use HashMap.put(k, v), it will digit k.hashCode() so that it can know where to put it.
And it also find the value by this number(k.hashCode());
You can see the ArrayList.hashCode() function and it is in the abstract class of AbstractList. Obviously, after we add some object, it will change the haseCode value. So we can not find the value use HashMap.get(K) and there is no element which hashCode is K.
public int hashCode() {
int hashCode = 1;
for (E e : this)
hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
return hashCode;
}

Java Hashtable problem

I am having some problem with java hashtable. Following is my hastable key and values
{corpus\2.txt=[cat sparrow], corpus\4.txt=[elephant sparrow], corpus\1.txt=[elephant cow], corpus\3.txt=[cow cat]}
So if i want to access first tuple i have to pass key "corpus\2.txt" to get its value. If i pass value i can get it's key. But I want to make a function I pass like 1 2 3 4 etc. and get both key and value. Any idea?
2nd question:
Is it possible to store an index with key and value too?? Or is it possible to get index ( 0,1,2,3 etc. ) from existing hashtable?
Thanks !
For starters, I would use a HashMap, rather than the (now obsolete) HashTable. If you do that, then you can use Map.Entry to return a key/value pair (as per your first question).
You can't easily store an index with your key. You might want to create a special Key object thus:
public class Key {
private String name;
private int index;
....
}
with a suitable equals()/hashCode() implementation (as pointed out below in the comments) and use that as the key in your HashMap. You've have to perform a lookup using this key and thus construct one from your current String-based key, but I don't think that's a big deal.
There is no method in the API to get a specific entry from a Java hash table. You can access the collection of all entries with the entrySet method, and iterating over that you will get all the key-value pairs as Map.Entry objects.
Hash tables are completely unordered. They are just mappings from keys to values and do not have any definite indices. There is a specific order that the entries will be processed if you iterate over the entrySet result, but this might also change when you modify the hash table.
Take a look at LinkedHashMap, a map implementation that preserves input ordering.
Rather use a Map<Integer, ValueObject> wherein ValueObject is just a custom javabean class with two properties e.g. filename and description.
Basic kickoff example:
public class ValueObject {
private String filename;
private String description;
public ValueObject() {
// Always keep default constructor alive.
}
public ValueObject(String filename, String description) {
this.filename = filename;
this.description = description;
}
// Add/generate public getters and setters for filename and description.
}
which you can use as follows:
Map<Integer, ValueObject> map = new HashMap<Integer, ValueObject>();
map.put(1, new ValueObject("corpus1.txt", "elephant cow"));
map.put(2, new ValueObject("corpus2.txt", "cat sparrow"));
map.put(3, new ValueObject("corpus3.txt", "cow cat"));
map.put(4, new ValueObject("corpus4.txt", "elephant sparrow"));
ValueObject vo = map.get(1); // Returns VO with corpus1.txt and elephant cow.
There's no way to access a Map by index. However, if what you really want to do is access the key-value pairs in the map one by one, you can just do:
for (Map.Entry<String, List<String>> nameAndWords: hashmap) {
String name = nameAndWords.getKey();
List<String> words = nameAndWords.getValue();
// do your stuff here
}
If you actually need indexing, you can add an external order to the map by keeping the keys in a list, which must be updated when you edit the map:
HashMap<String, List<String>> wordsByCorpus;
List<String> corpusNames;
public void addCorpus(String name, List<String> words) {
List<String> oldValue = wordsByCorpus.put(name, words);
if (oldValue == null) corpusNames.add(name);
}
public void removeCorpus(String name) {
wordsByCorpus.remove(name);
corpusNames.remove(name);
}
public Map.Entry<String, List<String>> getCorpus(int i) {
String name = corpusNames.get(i);
List<String> words = wordsByCorpus.get(name);
return wordsByCorpus.new SimpleImmutableEntry(name, words); // 1.6 only!
}
You either want to use a LinkedHashMap which allows you to access values added to the map using the index of the order they were added in.
Or you want to use 2 HashMaps. One to index by the string value and the second one to convert the integer value into the string value key of the first map. Then simple to get key and value from index:
String key = mapByIntToStringKey.get(index);
V value = mapByStringKey.get(key);
// now have both key and value, no linear searching so should be fast
Thus your maps would contain:
mapByStringKey={corpus\2.txt=[cat sparrow], corpus\4.txt=[elephant sparrow], corpus\1.txt=[elephant cow], corpus\3.txt=[cow cat]}
mapByIntToStringKey{2=corpus\2.txt, 4=corpus\4.txt, 1=corpus\1.txt}
although this is assuming that all your keys are not simply "corpus"+index+".txt".
If all keys are as above then if the indexes are not sparse then you could use a simple ArrayList (previously mentioned) and use get(index) which is fast (directly looks up in an array, can't get much faster than that), and then reconstruct the string key using the expression above.
If the indexes are sparse (i.e. some are missing, there are gaps) then just use the mapByIntToStringKey but replace with mapByIntToValue and reconstruct any string key you need using previous string expression.
The current high answer seems very odd to me, in that the suggestion is to key the map using the int index bit only of a compound key. Unless I'm reading it wrong, it means that you loose the ability to lookup values in the map using the string key alone or maybe just implies that you can always deduce the int index from the string key.

Categories

Resources