tags:

views:

545

answers:

6

Hi All, 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 !

+3  A: 

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.

Brian Agnew
You'll need to (correctly) implement hashCode and equals - if you base it only on the index member, you can then use that as a hacked "index" into your hash map.
Steven Schlansker
@Steven - thx for highlighting that. I've amended appropriately.
Brian Agnew
this is why I don't like Java. in other languages you solve this problem by using tuples, which implement comparing, equals, and hashcode for you
Claudiu
My headache with tuples is that they package up data *without* the use of objects. So if/when you need to provide behaviour to this data pairing, you have to replace the tuple with an object (as above). I've found this problem with Scala, which is seductive in its encouragement of such things :-)
Brian Agnew
A: 

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.

jk
A: 

Take a look at LinkedHashMap, a map implementation that preserves input ordering.

Steve B.
Maybe he doesn't have a `corpus5.txt`, but do a `corpus6.txt`.
BalusC
A: 

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.
BalusC
A: 

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!
}
Tom Anderson
A: 

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.

DaveC