What is the most straightforward way to create a hash table (or associative array...) in Java? My google-fu has turned up a couple examples, but is there a standard way to do this?
And is there a way to populate the table with a list of key->value pairs without individually calling an add method on the object for each pair?
Map map = new HashMap();
Hashtable ht = new Hashtable();
Both classes can be found from the java.util package. The difference between the 2 is explained in the following jGuru FAQ entry.
You can use double-braces to set up the data. You still call add, or put, but it's less ugly:
private static final Hashtable<String,Integer> MYHASH = new Hashtable<String,Integer>() {{
put("foo", 1);
put("bar", 256);
put("data", 3);
put("moredata", 27);
put("hello", 32);
put("world", 65536);
}};
Also don't forget that both Map and Hashtable are generic in Java 5 and up (as in any other class in the Collections framework).
Map<String, Integer> numbers = new HashMap<String, Integer>();
numbers.put("one", 1);
numbers.put("two", 2);
numbers.put("three", 3);
Integer one = numbers.get("one");
Assert.assertEquals(1, one);
import java.util.HashMap;
Map map = new HashMap();
What Edmund said.
As for not calling .add all the time, no, not idiomatically. There would be various hacks (storing it in an array and then looping) that you could do if you really wanted to, but I wouldn't recommend it.
And is there a way to populate the table with a list of key->value pairs without individually calling an add method on the object for each pair?
One problem with your question is that you don't mention what what form your data is in to begin with. If your list of pairs happened to be a list of Map.Entry objects it would be pretty easy.
Just to throw this out, there is a (much maligned) class named java.util.Properties that is an extension of Hashtable. It expects only String keys and values and lets you load and store the data using files or streams. The format of the file it reads and writes is as follows:
key1=value1
key2=value2
I don't know if this is what you're looking for, but there are situations where this can be useful.
It is important to note that Java's hash function is less than optimal. If you want less collisions and almost complete elimination of re-hashing at ~50% capacity, I'd use a Buz Hash algorithm Buz Hash
The reason Java's hashing algorithm is weak is most evident in how it hashes Strings.
"a".hash() give you the ASCII representation of "a" - 97, so "b" would be 98. The whole point of hashing is to assign an arbitrary and "as random as possible" number.
If you need a quick and dirty hash table, by all means, use java.util. If you are looking for something robust that is more scalable, I'd look into implementing your own.
Hashtable<Object, Double> hashTable = new Hashtable<>();
put values
...
get max
Optional<Double> optionalMax = hashTable.values().stream().max(Comparator.naturalOrder());
if (optionalMax.isPresent())
System.out.println(optionalMax.get());
Related
I basically need to know if my HashMap has different keys that map to the same value. I was wondering if there is a way other than checking each keys value against all other values in the map.
Update:
Just some more information that will hopefully clarify what I'm trying to accomplish. Consider a String "azza". Say that I'm iterating over this String and storing each character as a key, and it's corresponding value is some other String. Let's say I eventually get to the last occurrence of 'a' and the value is already be in the map.This would be fine if the key corresponding with the value that is already in the map is also 'a'. My issue occurs when 'a' and 'z' both map to the same value. Only if different keys map to the same value.
Sure, the fastest to both code and execute is:
boolean hasDupeValues = new HashSet<>(map.values()).size() != map.size();
which executes in O(n) time.
Sets don't allow duplicates, so the set will be smaller than the values list if there are dupes.
Very similar to EJP's and Bohemian's answer above but with streams:
boolean hasDupeValues = map.values().stream().distinct().count() != map.size();
You could create a HashMap that maps values to lists of keys. This would take more space and require (slightly) more complex code, but with the benefit of greatly higher efficiency (amortized O(1) vs. O(n) for the method of just looping all values).
For example, say you currently have HashMap<Key, Value> map1, and you want to know which keys have the same value. You create another map, HashMap<Value, List<Key>> map2.
Then you just modify map1 and map2 together.
map1.put(key, value);
if(!map2.containsKey(value)) {
map2.put(value, new ArrayList<Key>);
}
map2.get(value).add(key);
Then to get all keys that map to value, you just do map2.get(value).
If you need to put/remove in many different places, to make sure that you don't forget to use map2 you could create your own data structure (i.e. a separate class) that contains 2 maps and implement put/remove/get/etc. for that.
Edit: I may have misunderstood the question. If you don't need an actual list of keys, just a simple "yes/no" answer to "does the map already contain this value?", and you want something better than O(n), you could keep a separate HashMap<Value, Integer> that simply counts up how many times the value occurs in the map. This would take considerably less space than a map of lists.
You can check whether a map contains a value already by calling map.values().contains(value). This is not as efficient as looking up a key in the map, but still, it's O(n), and you don't need to create a new set just in order to count its elements.
However, what you seem to need is a BiMap. There is no such thing in the Java standard library, but you can build one relatively easily by using two HashMaps: one which maps keys to values and one which maps values to keys. Every time you map a key to a value, you can then check in amortized O(1) whether the value already is mapped to, and if it isn't, map the key to the value in the one map and the value to the key in the other.
If it is an option to create a new dependency for your project, some third-party libraries contain ready-made bimaps, such as Guava (BiMap) and Apache Commons (BidiMap).
You could iterate over the keys and save the current value in the Set.
But, before inserting that value in a Set, check if the Set already contains that value.
If this is true, it means that a previous key already contains the same value.
Map<Integer, String> map = new HashMap<>();
Set<String> values = new HashSet<>();
Set<Integter> keysWithSameValue = new HashSet<>();
for(Integer key : map.keySet()) {
if(values.contains(map.get(key))) {
keysWithSameValue.add(key);
}
values.add(map.get(key));
}
I want to store some words and their occurrence times in a website, and I don't know which structure I should use.
Every time I add a word in the structure, it first checks if the word already exists, if yes, the occurrence times plus one, if not, add the word into the structure. Thus I can find an element very fast by using this structure. I guess I should use a hashtable or hashmap, right?
And I also want to get a sorted list, thus the structure can be ranked in a short time.
Forgot to mention, I am using Java to write it.
Thanks guys! :)
A HashMap seems like it would suit you well. If you need a thread-safe option, then go with ConcurrentHashMap.
For example:
Map<String, Integer> wordOccurenceMap = new HashMap<>();
"TreeMap provides guaranteed O(log n) lookup time (and insertion etc), whereas HashMap provides O(1) lookup time if the hash code disperses keys appropriately. Unless you need the entries to be sorted, I'd stick with HashMap." -part of Jon Skeet's answer in TreeMap or HashMap.
TreeMap is the better solution, if you want both Sorting functionality and counting words.
Custom Trie can make more efficient but it's not required unless you are modifying the words.
Define a Hashmap with word as the key and counter as the value
Map<String,Integer> wordsCountMap = new HashMap<String,Integer>();
Then add the logic like this:
When you get a word, check for it in the map using containsKey method
If key(word) is found, fetch the value using get and increment the value
If key(word) is not found, add the value using thw word as key and put with count 1 as value
So, you could use HashMap, but don't forget about multythreading. Is this data structure could be accessed throught few thread? Also, you could use three map in a case that data have some hirarchy (e.g. in a case of rakning and sort it by time). Also, you could look throught google guava collections, probably, they will be more sutabile for you.
Any Map Implementation Will Do. If Localized Changes prefer HashMap otherWise
ConcurrentHashMap for multithreading.
Remember to use any stemming Library.
stemming library in java
for example working and work logically are same word.
Remember Integer is immutable see example below
Example :
Map<String, Integer> occurrence = new ConcurrentHashMap<String, Integer>();
synchronized void addWord(String word) { // may need to synchronize this method
String stemmedWord = stem(word);
Integer count = occurrence.get(stemmedWord)
if(count == null) {
count = new Integer(0);
}
count ++;
occurrence.put(stemmedWord, count);
**// the above is necessary as Integer is immutable**
}
Which data structure would be more preferable for making a dictionary in Java ? What would be better a tree or a hash-table ?
A Map. Nothing else. If you want sorting, use a TreeMap. Otherwise: HashMap.
A Dictionary maps a (key-)word to it's description or translation.
I would use something like
Map<String,Integer> dictionary = Collections.synchronizedMap(new TreeMap<String,Integer>());
Instead of Integer as the value of a String key, you can use a Class object which probably can hold a list that contains all the positions of that word inside the document
There are methods for easy retrieval of key values from the TreeMap. Following is the way you get an iterator out of TreeMap.
Set<Entry<String,Integer>> set = dictionary.entrySet();
Iterator<Entry<String,Integer>> entryItr = set.iterator();
Entry<String,Integer> entry = null;
while(entryItr.hasnext()){
entry = entryItr.next();
// Do whatever you want.
}
I would use a Trie, especially for memory efficiency and also prefix lookups.
I have an implementation that implements the map interface under APL on github: https://github.com/Blazebit/blaze-utils/tree/c7b1fa586590d121d9f44c1686cb58de0349eb0b/blaze-common-utils
Check it out and maybe it fits your needs better than a simple map.
According to the lecture in Introduction to Algorithms of MIT, I would say it is better to go with hash-tables. Because you can do operations in O(1) instead of O(logn)
https://www.youtube.com/watch?v=0M_kIqhwbFo
I use a TreeMap as a 'key' inside another TreeMap
ie
TreeMap<TreeMap<String, String>, Object>
In my code 'object' is a personal construct, but for this intance I have used a string.
I have created a pair of TreeMaps to test the TreeMap.CompareTo() and TreeMap.HashCode() methods. this starts with the following...
public class TreeMapTest
public void testTreeMap()
{
TreeMap<String, String> first = new TreeMap<String, String>();
TreeMap<String, String> second = new TreeMap<String, String>();
first.put("one", "une");
first.put("two", "deux");
first.put("three", "trois");
second.put("une", "one");
second.put("deux", "two");
second.put("trois", "three");
TreeMap<TreeMap<String, String>, String> english = new TreeMap<TreeMap<String, String>, String>();
TreeMap<TreeMap<String, String>, String> french = new TreeMap<TreeMap<String, String>, String>();
english.put(first, "english");
french.put(second, "french");
From here I now call the the english item to see if it contains the key
if (english.containsKey(second))
{
System.out.println("english contains the key");
//throws error of ClassCastException: Java.util.TreeMap cannot be cast to
//Java.Lang.Comparable, reading the docs suggests this is the feature if the key is
//not of a supported type.
//this error does not occur if I use a HashMap structure for all maps, why is
//this key type supported for one map structure but not another?
}
However I should note that both HashMap and TreeMap point to the same HashCode() method in the AbstractMap parent.
My first thought was to convert my TreeMap to a HashMap, but this seemed a bit soppy! So I decided to apply the hashCode() method to the 2 treemap objects.
int hc1 = first.hashCode();
int hc2 = second.hashCode();
if(hc1 == hc2)
{
systom.out.printline("values are equal " + hc1 + " " + hc2);
}
prints the following
values are equal 3877431 & 3877431
For me the hashcode should be different as the key values are different, I can't find details on the implementation difference of the hashCode() method between HashMap and TreeMap.
Please not the following.
changing the Keys only to HashMap doesn't stop the ClassCastException error. Changing all the maps to a HashMap does. so there is something with the containsKey() method in TreeMap that isn't working properly, or I have missunderstood - can anyone explain what?
The section where I get the hashCode of the first and second map objects always produces the same output (no matter if I use a Hash or Tree map here) However the if(english.ContainsKey(second)) doesn't print any message when HashMaps are used, so there is obviously something in the HashMap implementation that is different for the compareTo() method.
My principle questions are.
Where can I find details of the types of keys for use in TreeMap objects (to prevent future 'ClassCastException' errors).
If I can't use a certain type of object as a key, why am I allowed to insert it as a key into the TreeMap in the first place? (surely if I can insert it I should be able to check if the key exists?)
Can anyone suggest another construct that has ordered inster / retrieval to replace my TreeMap key objects?
Or have I potentially found strange behaviour. From my understanding I should be able to do a drop in replacement of TreeMap for HashMap, or have I stumbled upon a fringe scenario?
Thanks in advance for your comments.
David.
ps. the problem isn't a problem in my code as I use a personal utility to create a hash that becomes dependent on the Key and Value pairs (ie I calculate key hash values differently to value hash values... sorry that if is a confusing sentence!) I assume that the hashCode method just sums all the values together without considering if a item is a key or a value.
pps. I'm not sure if this is a good question or not, any pointers on how to improve it?
Edit.
from the responses people seem to think I'm doing some sort of fancy language dictionary stuff, not a surprise from my example, so sorry for that. I used this as an example as it came easily to my brain, was quick to write and demonstrated my question.
The real problem is as follows.
I'm accessing a legacy DB structure, and it doesn't talk nicely to anything (result sets aren't forward and reverse readable etc). So I grab the data and create objects from them.
The smallest object represents a single row in a table (this is the object that in the above example I have used a string value 'english' or 'french' for.
I have a collection of these rowObjects, each row has an obvious key (this is the TreeMap that points to the related rowObject).
i don't know if that makes things any clearer!
Edit 2.
I feel I need to elaborate a little further as to my choice of originaly using
hashMap<HashMap<String,string>, dataObject>
for my data structure, then converting to TreeMap to gain an ordered view.
In edit 1 I said that the legacy DB doesn't play nicely (this is an issue with the JDBC.ODBC I suspect, and I'm not about to acquire a JDBC to communicate with the DB). The truth is I apply some modifications to the data as as I create my java 'dataObject'. This means that although the DB may spit out the results in ascending or descending order, I have no way of knowing what order they are inserted into my dataObject. Using a likedHashMap seems like a nice solution (see duffymo's suggestion) but I later need to extract the data in an ordered fashion, not just consecutively (LinkedHashMap only preserves insertion order), and I'm not inclined to mess around with ordering everything and making copies when I need to insert a new item in between 2 others, TreMap would do this for me... but if I create a specific object for the key it will simply contain a TreeMap as a member, and obviously I will then need to supply a compareTo and hashCode method. So why not just extent TreeMap (allthough Duffymo has a point about throwing that solution out)!
This is not a good idea. Map keys must be immutable to work properly, and yours are not.
What are you really trying to do? When I see people doing things like this with data structures, it makes me think that they really need an object but have forgotten that Java's an object-oriented language.
Looks like you want a crude dictionary to translate between languages. I'd create a LanguageLookup class that embedded those Maps and provide some methods to make it easier for users to interact with it. Better abstraction and encapsulation, more information hiding. Those should be your design objectives. Think about how to add other languages besides English and French so you can use it in other contexts.
public class LanguageLookup {
private Map<String, String> dictionary;
public LanguageLookup(Map<String, String> words) {
this.dictionary = ((words == null) ? new HashMap<String, String>() : new HashMap<String, String>(words));
}
public String lookup(String from) {
return this.dictionary.get(from);
}
public boolean hasWord(String word) {
return this.dictionary.containsKey(word);
}
}
In your case, it looks like you want to translate an English word to French and then see if the French dictionary contains that word:
Map<String, String> englishToFrenchWords = new HashMap<String, String>();
englishToFrenchWords.put("one", "une");
Map<String, String> frenchToEnglishWords = new HashMap<String, String>();
frenchToEnglishWords.put("une", "one");
LanguageLookup englishToFrench = new LanguageLookup(englishToFrenchWords);
LanguageLookup frenchToEnglish = new LanguageLookup(frenchToEnglishWords);
String french = englishToFrench.lookup("one");
boolean hasUne = frenchToEnglish.hasWord(french);
Your TreeMap is not Comparable so you can't add it to a SortedMap and its not immutable so you can't add it to a HashMap. What you could use an IdentityMap but suspect an EnumMap is a better choice.
enum Language { ENGLISH, FRENCH }
Map<Language, Map<Language, Map<String, String>>> dictionaries =
new EnumMap<>(Language.class);
Map<Language, Map<String, String>> fromEnglishMap = new EnumMap<>(Language.class);
dictionaries.put(Language.ENGLISH, fromEnglishMap);
fromEnglishMap.put(Language.FRENCH, first);
Map<Language, Map<String, String>> fromFrenchMap = new EnumMap<>(Language.class);
dictionaries.put(Language.FRENCH, fromFrenchMap);
fromEnglishMap.put(Language.ENGLISH, second);
Map<String, String> fromEnglishToFrench= dictionaries.get(Language.ENGLISH)
.get(Language.FRENCH);
To the problem why Hashmap works and Treemap does not:
A Treemap is a "sorted map", meaning that the entries are sorted according to the key. This means that the key must be comparable, by implementing the Comparable interface. Maps usually do NOT implement this, and I would highly suggest you do not create a custom type to add this feature. As duffymo mentions, using maps as keys is a BAD idea.
This should be easy for many of you, but for me it's just another bit of rust needing to be chipped away as I get back into basic Java coding. Using bloody associative arrays for so long in other languages have turned me nice and spoiled. :P
My problem is simple: I'm storing a set of objects, each containing a string and a number, in a list. I would like each object inserted into this list to be sorted alphabetically by its string. I would also like to be able to retrieve objects from the list by their string as well. I would like to do this as formally and/or efficiently as possible.
Is there something already available in the Java standard libraries for this?
there is a great writeup on java collections which covers most of your needs.
short advice concerning this: use a TreeMap(Comparator c) with a custom Comparator.
key ist the string, value is the composite object with string and number
That sound like a SortedMap. With the String as the key and the Number as the value.
Apart from the SortedMap, you could have a TreeSet<Pair<String, Number>> where you supply the comparator to sort the pairs (or make your Pair class implement Comparable and do it there).
This keeps the objects separate from the data structure, and whilst for a trivial example like this it isn't a big deal, you can imagine that a TreeSet<MyObject> where MyObject implements Comparable is easier to grok in the long term.
If you have duplicate string value among the objects in the list, you might want to look at
Google Collections' TreeMultimap. With TreeMultimap, not only the keys are sorted but all values having the same key are also stored in a collection.
Multimap<String, Pair> mm = new TreeMultimap<String, Pair>(
new Comparator<String>(){...},
new PairComparator());
mm.put("A", new Pair("A", 1));
mm.put("B", new Pair("B", 2));
mm.put("B", new Pair("B", 3));
Collection values = mm.values();
// values are [Pair("A", 1), Pair("B", 2), Pair("B", 3)]
Collection bValues = mm.get("B");
// bValues are [Pair("B", 2), Pair("B", 3)]
I have done something similar to that, I used ArrayList to store them objects and write comparators for sorting the arraylist.