Java Hashtable problem - java

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.

Related

Creating an array that stores strings and integers in java

I would like to create an array that stores the names (String) and values (integer) of company stocks, but I don't know how to go about it.
An Object[] can hold both String and Integer objects. Here's a simple example:
Object[] mixed = new Object[2];
mixed[0] = "Hi Mum";
mixed[1] = Integer.valueOf(42);
...
String message = (String) mixed[0];
Integer answer = (Integer) mixed[1];
However, if you put use an Object[] like this, you will typically need to use instanceof and / or type casts when accessing the elements.
Any design that routinely involves instanceof and/or type casts needs to be treated with suspicion. In most cases, there is a better (more object-oriented, more efficient, less fragile) way of achieving the same ends.
In your particular use-case, it sounds like what you really need is a mapping object that maps from String (names) to Integer (numbers of stocks). And the nice thing about Java is that there are existing library classes that provide this functionality; e.g. the HashMap<K,V> class, with String as the key type and Integer as the value type.
Another possibility might be an array, List or Set of some custom or generic pair class. These have different semantic properties to Map types.
You have two choices:
Use an array.
public class Value {
public String name;
public int number;
}
...
public Value[] values = new Value[10];
....
Use a map which has much more comfort, specially you can use the name as key to get a value
....
public Map<String, int> valueMap = new HashMap<String,int>();
valueMap.put("Sample",10);
int value = valueMap.get("Sample");
...
You can use a Map data structure instead of an array. This is basically a type of Collection that has key-value pairs. Your string name can be used as the key and the value is your integer.
Map<String,Integer> myMap = new HashMap<String, Integer>;
MyMap.put("someone", 6);
Note that using a HashMap has a speed advantage over an array during lookup. The complexity of HashMap lookup is O(log(n)) while that of an array is O(n).

Pull out the a spefic "rank" from an HashMap not yet sorted which also contains different values but same key or better same count;

I have this HashMap containing words and the count for each word from a given text file;
{word=1, word2=1, word3=2, word4=1, word5=1, word6=4, word7=1, word8=1};
i was following your suggestion in other topics; but i have notice that if use fro example sorted Collections and i search for a specific KEY which could be 1 in this case it only return me one word while instead can return more values for same key;
the point is between all the collections:
Lists
Maps
ArrayLists
Trees
HashMaps
HashTables
which is the most advisable to use?
on my Class the user will input an int and that int will correspond to the 1st or 2nd or 3rd or 4th and so on..... words used in the files base on the count and occurences;
it's challenging
so far i have managed to store in hashmap and eventually order it in a Tree by Desc Key; so first element will be the greater; but still the algorithm needs more sense;
ps. i do not expect solution or pieces of codes but a good input to start ... a very good advise or direction best to follow;
Maps, by nature, store (will return) only one element per key. That means that if you'll store [key:1, val:a] and then store again [key:1, val:2]. The second insertion will override the first and when you'll "get" key:1 the returned result will be b.
You can, however, to store a List per key. This list can store all the value values per the same key.
So we'll declare the map that we'l use as follows:
Map<String, LinkedList<String>> map = new HashMap<>();
This is how insert should look like:
public void insert(String key, String value){
List<String> values = map.get(key);
if (values == null){ // this is the first time we use this key
values = new LinkedList<String>(); // so we need to create a new values List
}
values.add(value);
map.put(key, values)
}
the "get" is pretty straightforward:you get the list of values and if it's not null - iterate the values and print/do whatever you want with them.
public List<String> get(String key){
return map.get(key);
}
If I understand you correctly, you have a Map<String,Integer> map; which maps words to their frequencies, and now you want to look up words by frequency.
Create a new map that Map<Integer,List<String>> and fill it using the first map:
Map<Integer,List<String>> reverseMap = new HashMap<>();
for (Map.Entry<String,Integer> entry : map.entrySet()) {
List<String> list = reverseMap.get(entry.getValue());
if (list == null) {
reverseMap.put(entry.getValue(), list = new ArrayList<>());
}
list.add(entry.getKey());
}
You will get a map like:
java.util.HashMap[3] {
1=[word2, word4, word, word5, word7, word8]
2=[word3]
4=[word6]
}
In this map, each key is the frequency, each value is a list of words having that frequency.
Edit: To pull out the words having the second-most used frequency ("rank 2"), generate a list of the most used frequencies:
List<Integer> frequencies = new ArrayList<>(reverseMap.keySet());
Collections.sort(frequencies, Collections.reverseOrder());
Then:
System.out.println(reverseMap.get(frequences.get(2 - 1)));
Or, to sort the entire map in descending order of frequency (4, 2, 1), declare it as a TreeMap instead of a HashMap, with a reverseOrder comparator:
Map<Integer,List<String>> reverseMap = new TreeMap<>(Collections.reverseOrder());

HashMap overrides the nextvalue 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.

Chaining in HashMap

Code:
public static void main(String[] args) {
Map<String,String> map= new HashMap<String,String>();
map.put("a", "s");
map.put("a", "v");
System.out.println(map.get("a"));
}
Now, as per my understanding, since the key values in both the put case is the same i.e. a, collision is bound to happen, and hence chaining occurs. [Correct me if I am wrong].
Now if I want to retrieve the list of all the values mapped to key value a, how do i get it?
Right now my println prints v only.
This has nothing to do with collision or chaining: you're replacing the old value of a with a new value.
A map keeps unique keys. collision/chaining will occur in a hash data structure when two distinct keys happen to get the same hash value based on the particular hash function. Or in java, you can explicitly create an object that returns the same value for hashCode().
If you want mapping with multiple values for a key, then you'll need to use a different data structure/class.
Like other people already suggested, there is no such thing as Collision for your case.
It's simply because Hashmap only accepts an unique key.
However you can have an alternative if you want the key to be not unique, for example Google Guava Multimap or Apache Multimap
Example using Google lib:
public class MutliMapTest {
public static void main(String... args) {
Multimap<String, String> myMultimap = ArrayListMultimap.create();
// Adding some key/value
myMultimap.put("Fruits", "Bannana");
myMultimap.put("Fruits", "Apple");
myMultimap.put("Fruits", "Pear");
myMultimap.put("Vegetables", "Carrot");
// Getting the size
int size = myMultimap.size();
System.out.println(size); // 4
// Getting values
Collection<string> fruits = myMultimap.get("Fruits");
System.out.println(fruits); // [Bannana, Apple, Pear]
Collection<string> vegetables = myMultimap.get("Vegetables");
System.out.println(vegetables); // [Carrot]
// Iterating over entire Mutlimap
for(String value : myMultimap.values()) {
System.out.println(value);
}
// Removing a single value
myMultimap.remove("Fruits","Pear");
System.out.println(myMultimap.get("Fruits")); // [Bannana, Pear]
// Remove all values for a key
myMultimap.removeAll("Fruits");
System.out.println(myMultimap.get("Fruits")); // [] (Empty Collection!)
}
}
See the java doc for put
Associates the specified value with the specified key in this map (optional operation). If the map previously contained a mapping for the key, the old value is replaced by the specified value. (A map m is said to contain a mapping for a key k if and only if m.containsKey(k) would return true.)
The collision happens when two different keys comes up with the same hashcode and not when two same keys.
class StringKey {
String text;
public StringKey() {
text = "";
}
public StringKey(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
#Override
public int hashCode() {
if (text != null) {
text.substring(0, 1).hashCode();
}
return 0;
}
#Override
public boolean equals(Object o) {
if (o instanceof StringKey) {
return ((StringKey) o).getText().equals(this.getText());
}
return false;
}
public static void main(String[] args) {
Map<StringKey, String> map = new HashMap<StringKey, String>();
StringKey key1 = new StringKey("a");
StringKey key2 = new StringKey("b");
map.put(key1, "s");
map.put(key2, "v");
System.out.println(map.get(key1));
System.out.println(key1.hashCode() + " " + key2.hashCode() + " " + key1.equals(key2));
}
}
The output is
s
0 0 false
now this will cause a collision; but you can not interpret this from the output of map keys and values.
The second put() simply overwrites what the first put() wrote. There is no chaining.
Second put replaces first put, so you will have only one value with key "a" in Hashmap.
So your map just contains
map.put("a", "v");
Now,as per my understanding, since the key values in both the put case
is the same i.e. a, collision is bound to happen, and hence chaining
occurs. [Correct me if i am wrong].
You're wrong. Thats not how a Map works. Consider using a MultiMap from Google's Guava library.
You can always roll your own:
Map<String, ArrayList<String>>();
You will have to make your HashMap as follows
public static void main(String[] args) {
HashMap<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
if ( map.get("a") == null ){
map.put("a", new ArrayList<String>());
}
ArrayList<String> innerList = map.get("a");
innerList.add("s");
innerList.add("v");
map.put("a",innerList);
System.out.println(map.get("a"));
}
Hashing algorithm used in HashMaps are pretty vague in the first go. Internally a HashMap is nothing but an array with indices. The index here is usually referred to as 'hashValue'. As the hashValue is the index of an element in the array, it has to be less than the size of the HashMap itself.The HashMap's hashing algorithm converts the key's hashcode into the hashValue. This is where the Map stores the Entry (key-value pair).
When an element is put into a Map, it generates the hashValue from the element key's hashcode, and stores the Entry into the array at this index, which is nothing but the hashValue.
Now, hashing algorithm can be efficient to a certain extent only, that is we can never assure that the hashValue generated for two different keys are always different. It could be same under two conditions:
1) The keys are same (as in your case)
2) The Keys are different, but the hashValue generated for both the keys are same.
We simply cannot replace the value of the Entry at the hashValue position in the array, as this will violate the second condition, which is very valid. This is where the equals() comes into picture. Now, the HashMap checks for the equality between the new key and the key that exists in that index's Entry. If both the keys are same it means replacement, else it's collision and the HashMap uses the appropriate collision technique.
Now, if you want the list of all the values that you put for a particular key, consider using a composite map
HashMap<String, List<String>>.
Both the keys you tried to put in the HashMap has the same HashCode. Thus the first value gets overwritten an you will end up having only one value in the HashMap.
You can put Two similar objects in the same HashMap by overriding thier hashCode() Method.
Further notes on when Chaining actually takes place when a HashMap is used:
The Java implementation for HashMap will either override a key or chain an object to it depending on the following:
You put an object foo as key, with hash code X into the map
You put another object bar (as key..) that has the same hash code X
into the map
Since the hashes are the same, the algorithm would need to put the
object bar on the same index where foo is already stored. It would then consult the equals method of foo, to determine whether it should chain bar to foo (i.e foo.next() will become bar) or override foo with bar:
3.1.If equals returns true, foo & bar are either the same object, or they are semantically the same, and overriding will take place rather than chaining.
3.2. If equals returns false, foo & bar are treated as two distinct entities and chaining will take place. If you then print your HashMap, you'll be seeing both foo and bar.

What is the Best Way to Store some data in Java? (Array vs ArrayList)

So currently, I am extracting two different attributes from an XML file in java that (for my project) are related to each other and just printing them out to the console. However, I want to be able to store these in a way in which referencing one value will retrieve it's corresponding counterpart. For example:
Id: rId11 & Target: image3
Id: rId10 & Target: image2
Id: rId9 & Target: image1
With those 3 values, I'd want a way to store each line, but when I reference "rId" I could get it's corresponding "Target" value. I was thinking about using either an array or an arrayList, but I'm not really sure which would be better for my purposes or how exactly I would go about referencing only one value and getting the other. Could anyone offer me some advice? Thank you in advance.
If your keys are unique, use a Map.
Map<String, String> mak = new HashMap<String, String>();
map.put("rId11","image3");
map.put("rId10","image2");
map.put("rId9","image1");
Reference:
Java Tutorial > The Map
Interface
Otherwise, create a custom Object that holds key and value and create a List (or Set???) of these.
public class Entry {
private final String id;
private final String value;
public Entry(String id, String value) {
this.id = id; this.value = value;
}
public String getId() { return id; }
public String getValue() { return value; }
// also implement equals() and hashCode(), please
}
List<Entry> entries = new ArrayList<Entry>();
entries.add(new Entry("rId11","image3"));
Reference:
Java Tutorial > The List Interface
Java Tutorial > The Set Interface
Use a Map, with the Id ad the key and the Target as the value. Note that Map is an interface and thus defines behavior only. You will need to pick a specific implementation, such as HashMap.
I think a java.util.HashMap would be better suited for this requirement especially if sorting is not required.
// not sure what types these are but this would work better
Map<String, String> m = new HashMap<String, String>();
m.put("rId11", "image3");
String other = m.get("rId11");
If i understand correctly, you want to be able to do look for something like "rId10" and get the value "image2" (and only that).
If that is the case,I think the best (in terms of speed) and easiest solution will be a hash table (java.util.Hashtable) - be careful to use Java Generics as well (after Java 1.5). Check out http://en.wikipedia.org/wiki/Hash_table also.
You're being a bit ambiguous about what you want. If you want to lookup a value based on a given key, then store the pairs in a HashMap (faster) or Hashtable (slower but thread-safe).
Primitive arrays (and more advanced List-based collections such and ArrayList or Vector) don't work with name-value pairs out of the box. They are simply, well... lists. Primitive arrays can offer a bit more performance, since you avoid creating objects, but the more advanced List-type collections can be safer and more flexible.
Still, it sounds (?) like you want a Map type collection rather List type one.
UPDATE: By the way, if you use a Map then you can still work with a list of all your "rId" values. It will be a Set datatype actually, but that's just a special cousin of List that doesn't allow duplicates:
Map<String, String> myMap = new HashMap<String, String>();
myMap.put("rId11","image3");
// ... additional put's for the other values
Set<String> myRids = myMap.keySet();
for(String rId : myRids) {
// do whatever you want with each rId one-by-one, etc
// You could also use "myRids.iterator()" to work with an Iterator instead
}
If the "keys" to your target values will be unique and only ever have one target mapped to them, then I would recommend using java.util.HashMap instead. You can retrieve any target value by passing in the key. Plus you can Iterate over HashMap like you could an ArrayList.
public class Item {
private String id;
private String target;
public Item(String id, String target) {
this.id = id;
this.target = target;
}
public String getId() {
return this.id;
}
public String getTarget() {
return this.target;
}
}
List<Item> items = new ArrayList<Item>();
// or
Map<String, Item> itemsIndexedById = new HashMap<String, Item>();
// depending on your use-case
Read the Java tutorial about collections.
ArrayList is useful if you need to add elements to it dynamically

Categories

Resources