I've been using a lot Perl hashes due to super flexibility and convenient.
for instance, in Perl I can do the following:
$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}
I wondering how can I accomplish the same thing with Java, I guess it has something to do with HashMap?
Thanks,
I've been using a lot Perl hashes due to super flexibility and convenient. for instance, in Perl I can do the following:
$hash{AREA_CODE}->{PHONE}->{STREET_ADDR}
I wondering how can I accomplish the same thing with Java, I guess it has something to do with HashMap?
The Java code which approximates the following Perl code:
my %hash;
$hash{AREA_CODE}{PHONE}{STREET_ADDR} = "221B Baker Street";
printf "Street address is %s\n", $hash{AREA_CODE}{PHONE}{STREET_ADDR};
is
HashMap<String, HashMap<String, HashMap<String, String>>> hash =
new HashMap<String, HashMap<String, HashMap<String, String>>>();
hash.put("AREA_CODE", new HashMap<String, HashMap<String, String>>());
hash.get("AREA_CODE").put("PHONE", new HashMap<String, String>());
hash.get("AREA_CODE").get("PHONE").put("STREET_ADDR", "221B Baker Street");
System.out.printf("Street address is %s\n",
hash.get("AREA_CODE").get("PHONE").get("STREET_ADDR"));
Isn’t that special? :)
I say ‘approximates’ for many reasons. One of these is that in Java you’ll be frustrated to the point of extreme apoplexy merely for wanting to then do on the next line of Java the equivalent of this perfectly straightforward Perl code:
$hash{AREA_CODE}{PREFIX} = 800;
If you want Perl’s flexibility and convenience in things like this, Java simply isn’t going to give it to you. Even worse, its partisans will often berate you for even expressing such a desire.
First of all, your specific example ($hash{AREA_CODE}->{PHONE}->{STREET_ADDR}), with hard-coded strings as hash keys, is not really a useful data structure in Java as Michael Carman pointed out - it should be stored as a class with attributes (and to be honest it's a bad data structure in concept - data like this is more likely to be an array of phones, not hash of phones).
Second, assuming you actually meant $hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR}, it looks like everyone's Java code so far was NOT implementing a generic equivalent code - the code all assumed that the Java hash is newly initialized for storing example OR fully populated for retrieval example (in other words, as leonbloy's answer noted, is missing autovivification feature).
The correct code mimiquing autovivification is:
// This method will ensure that hash-of-hash-of-hashes structure exists of a given set of 3 keys.
public HashMap<String, HashMap<String, HashMap<String, Object>>>
autovivification_3rd_level (
HashMap<String, HashMap<String, HashMap<String, Object>>> hash
, String AREA_CODE, String PHONE, String STREET_ADDR) {
if (hash == null) {
hash = new HashMap<String, HashMap<String, HashMap<String, Object>>>();
}
if (!hash.contains(AREA_CODE) || hash.get(AREA_CODE) == null) {
hash.put(new HashMap<String, HashMap<String, Object>>());
}
HashMap<String, HashMap<String, Object>> AREA_CODE_hash
= (HashMap<String, HashMap<String, Object>>) hash.get(AREA_CODE);
if (!AREA_CODE_hash.contains(PHONE) || AREA_CODE_hash.get(PHONE) == null) {
AREA_CODE_hash.put(new HashMap<String, Object>());
}
return hash;
}
////////////////////////////////////////////////////////////////////////////////////
// Equivalent to Perl's "$hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR} = value;"
public Object put_3d_level_hash(
HashMap<String, HashMap<String, HashMap<String, Object>>> hash
, String AREA_CODE, String PHONE, String STREET_ADDR,
, Object value) {
hash = autovivification_3rd_level(hash, AREA_CODE, PHONE, STREET_ADDR);
return hash.get(AREA_CODE).get(PHONE).put(STREET_ADDR, value);
}
put_3d_level_hash(hash, AREA_CODE, PHONE, STREET_ADDR, obj);
////////////////////////////////////////////////////////////////////////////////////
// Equivalent to Perl's "$var = $hash{$AREA_CODE}->{$PHONE}->{$STREET_ADDR}"
public Object get_3d_level_hash(HashMap<String, HashMap<String, HashMap<String, Object>>> hash
, String AREA_CODE, String PHONE, String STREET_ADDR) {
hash = autovivification_3rd_level(hash, AREA_CODE, PHONE, STREET_ADDR);
return hash.get(AREA_CODE).get(PHONE).get(STREET_ADDR);
}
Object obj = get_3d_level_hash(hash, AREA_CODE, PHONE, STREET_ADDR);
See the Map interface and its implementations, specially HashMap.
Beware that Java doesn't have Perl's auto-vivification (handy but dangerous feature) so that
hash.get("areaCode").get("phone").get("streetAdr")
will throw an exception if, eg, get(phone) returns null.
Beware also that you should not uses hashes for things that have fixed names ("properties"), you should define your own classes with its getters and setters.
Java has hashes, but because of strong typing they're not quite as flexible as hashes in Perl. Multidimensional hashes are harder to work with. In Perl, you can just declare a hash and let autovivification create the nested hashes on demand.
my %hash;
$hash{a}{b} = 1;
In Java, you have to declare it to be a hash-of-hashes up-front.
Map<String,Map<String,Integer>> hash = new HashMap<String,HashMap<String,Integer>>();
hash.put("a", new HashMap<String, Integer>());
hash.get("a").put("b", new Integer(1));
For every extra dimension you need to add another nesting of Map<K,V> to the declaration. Aside from being tedious, this isn't very OO.
If the hash keys are constant, why won't hash.getAreaCode().getPhone().getStreetAddr() do? Keep in mind that either your getters or your constructors will need to handle default value generation.
You can easily subclass your hash to add a method that'll autovivify for you.
From: $hash{AREA_CODE}->{PHONE}->{STREET_ADDR}
To: hash.vivifyingGet(areaCode).put(phone, streetAddr).
Assuming I've created the hash with:
/**
* A two-level autovivifying hashmap of X and Y to Z. Provides
* a new method #vivifyingGet(X) which creates the next level of hash.
*/
Map<AreaCode, Map<Phone, StreetAddr>> hash =
new HashMap<AreaCode, Map<Phone, StreetAddr>>() {
/**
* Convenience method to get or create the next level of hash.
* #param key the first level key
* #return the next level map
*/
public Map<Phone, StreetAddr> vivifyingGet(Phone key) {
if (containsKey(key)) {
return get(key);
} else {
Map<Phone, StreetAddr> = hash = new HashMap<Phone, StreetAddr>();
put(key, hash);
return hash;
}
}
};
I missed the perl hashes a lot in my work and made some ugly workarounds with hash classes.
Last week I had an idea to implement the whole thing in one PerlMap class which use delimiters to access objects and foremost the Lists zu access subsets.
It works fine with map.get(code:street:phone) and map.put(code:street:phone,"123456789"). To get a list of phonenumber you just use map.getList(code:street).
I've just started but use in my project now. It has no limitations of complexity :-) and you can choose the delimiter free. I put the whole stuff under http://www.jdeer.org. Have fun.
You're probably going to want to go with Groovy if you want this sort of flexibility but still run within the JVM. tchrist likes to ignore the point that Java is strong-typed as opposed to dynamic-typed languages like Perl or PHP - and also likes to ignore that Java is an order of magnitude faster at running, but that's just me being a "partisan", apparently.
Related
In swift I can declare a dictionary (key value pairs) like so
var toppings = [
"Onions":"Red",
"Peppers":"Green",
]
What is the equivalent (declare key value pairs) in Java?
I have tried modifying an array i.e. changing...
public String[] couplets = {
"Onions",
"Peppers",
};
...to...
public String[] toppings = {
"Onions":"Red",
"Peppers":"Green",
};
...but it does not work.
I appreciate they are different languages so likely I am oversimplifying this by trying to do a straight like for like.
Essentially I would like to create a static list of key value pairs in Java.
I have googled for suggestions but all the answers seem overly complicated compared to what I can do in swift so I am wondering if there is a straightforward way - Perhaps there isn't...
Any advice is much appreciated
Thanks
http://docs.oracle.com/javase/tutorial/collections/interfaces/map.html
A Map is an object that maps keys to values. A map cannot contain duplicate keys: Each key can map to at most one value.
Map<String,String> toppings = new HashMap<>();
toppings.put("Onions","Red");
toppings.put("Peppers","Green");
Maps are great, you will end up using them a lot :)
Try the Map.
Instanciate new Map :
Map<String, String> map = new HashMap<String, String>();
Put values :
map.put("Onions","Red");
Read values :
map.get("Onions"); will return "Red"
If you need work with a String key you should use an HashMap as suggested in other answers.
If you can use an Integer key, I suggest you using a SparseArray
SparseArray<String> values = new SparseArray<String>();
values.put(1,"value1");
values.put(2,"value2");
I am new to java and practicing by creating a simplistic NaiveBayes classifier. I am still new to object instantiation, and wonder what to do to initialize a HashMap of HashMaps. When inserting new observations into the classifier, I can create a new HashMap for an unseen feature name in a given class, but do I need to initialize?
import java.util.HashMap;
public class NaiveBayes {
private HashMap<String, Integer> class_counts;
private HashMap<String, HashMap<String, Integer>> class_feature_counts;
public NaiveBayes() {
class_counts = new HashMap<String, Integer>();
// do I need to initialize class_feature_counts?
}
public void insert() {
// todo
// I think I can create new hashmaps on the fly here for class_feature_counts
}
public String classify() {
// stub
return "";
}
// Naive Scoring:
// p( c | f_1, ... f_n) =~ p(c) * p(f_1|c) ... * p(f_n|c)
private double get_score(String category, HashMap features) {
// stub
return 0.0;
}
public static void main(String[] args) {
NaiveBayes bayes = new NaiveBayes();
// todo
}
}
Note this question is not specific to Naive Bayes classifiers, just thought I would provide some context.
Yes, you need to initialize it.
class_feature_counts = new HashMap<String, HashMap<String, Integer>>();
When you want to add a value to class_feature_counts, you need to instantiate it too:
HashMap<String, Integer> val = new HashMap<String, Integer>();
// Do what you want to do with val
class_feature_counts.put("myKey", val);
Recursive generic data structures, like maps of maps, while not an outright bad idea, are often indicative of something you could refactor - the inner map often could be a first order object (with named fields or an internal map), rather than simply a map. You'll still have to initialize these inner objects, but it often is a much cleaner, clearer way to develop.
For instance, if you have a Map<A,Map<B,C>> you're often really storing a map of A to Thing, but the way Thing is being stored is coincidentally a map. You'll often find it cleaner and easier to hide the fact that Thing is a map, and instead store a mapping of Map<A,Thing> where thing is defined as:
public class Thing {
// Map is guaranteed to be initialized if a Thing exists
private Map<B,C> data = new Map<B,C>();
// operations on data, like get and put
// now can have sanity checks you couldn't enforce when the map was public
}
Also, look into Guava's Mulitmap/Multiset utilities, they're very useful for cases like this, in particular they do the inner-object initializations automatically. Of note for your case, just about any time you implement Map<E, Integer> you really want a Guava Multiset. Cleaner and clearer.
You must create an object before using it via a reference variable. It doesn't matter how complex that object is. You aren't required to initialize it in the constructor, although that is the most common case. Depending on your needs, you might want to use "lazy initialization" instead.
Do not declare your variables with HashMap. It's too limiting.
Yes, you need to initialize class_feature_counts. You'll be adding entries to it, so it has to be a valid map. In fact, initialize both at declaration and not in the constructor since there is only one way for each to start. I hope you're using Java 7 by now; it's simpler this way.
private Map< String, Integer> classCounts = new HashMap<>();
private Map< String, Map< String, Integer>> classFeatureCounts = new HashMap<>();
The compiler will deduce the types from the <>. Also, I changed the variable names to standard Java camel-case style. Are classCounts and classFeatureCounts connected?
I am so confused right now. I am supposed to write a program that uses a hashtable. The hashtable holds words along with their frequency of use. The class "Word" holds a counter and the string. If the word is already in the table then its frequency increases. I have been researching how to do this but am just lost. I need to be pointed in the right direction. Any help would be great.
Hashtable<String, Word> words = new Hashtable<String, Word>();
public void addWord(String s) {
if (words.containsKey(s) {
words.get(s).plusOne();
} else {
words.put(s, new Word(s));
}
}
This will do it.
Hashtable would be an unusual choice for any new Java code these days. I assume this is some kind of exercise.
I would be slightly concerned by any exercise that hadn't been updated to use newer mechanisms.
HashMap will give you better performance than Hashtable in any single threaded scenario.
But as Emmanuel Bourg points out, Bag will do all of this for you without needing the Word class at all: just add String objects to the Bag, and the bag will automatically keep count for you.
Anyway, you're being asked to use a Map, and a map lets you find things quickly by using a key. The key can be any Object, and Strings are very commonly used: they are immutable and have good implementations of hashCode and equals, which make them ideal keys.
The javadoc for Map talks about how you use maps. Hashtable is one implementation of this interface, though it isn't a particularly good one.
You need a good key to let you find existing Word objects quickly, so that you can increment the counter. While you could make the Word object itself into the key, you would have some work to do: better is to use the String that the Word contains as the key.
You find whether the Word is already in the map by looking for the value object that has the String as its key.
You'd better use a Bag, it keeps the count of each element:
http://commons.apache.org/collections/api-release/org/apache/commons/collections/Bag.html
This piece of code should solve your problem
Hashtable <String, Word> myWords = new Hashtable<String, Word>();
Word w = new Word("test");
Word w = new Word("anotherTest");
String inputWord = "test";
if (myWords.containsKey(inputWord)){
myWords.get(inputWord).setCounter(myWords.get(inputWord).getCounter+1);
}
Given that the class Word has a counter and a string, I'd use a HashMap<String, Word>. If your input is an array of Strings, you can accomplish something like this by using:
public Map<String, Word> getWordCount(String[] input) {
Map<String, Word> output = new HashMap<String, Word>();
for (String s : input) {
Word w = output.get(s);
if (w == null) {
w = new Word(s, 0);
}
w.incrementValue(); // Or w = new Word(s, w.getCount() + 1) if you have no such function
output.put(s, w);
}
return output;
}
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
package datastrcutures;
import java.util.*;
public class java_hashtable {
public static void ratingofcity() {
Hashtable CityRating = new Hashtable();
CityRating.put("New York", "8");
CityRating.put("Sandton", "9");
}
}
I think you have a typo there, your object type has to be Hashtable instead of Hasttable And you should use Java Generics
Instantiate your hash table object like this:
Hashtable<String, String> cityRating = new Hashtable<String, String>();
And as Java naming convention I would suggest having your object name start with a lower case letter.
The question Is this correct usage of a hashtable is very subjective.
A Map is used to storing sets of keys and values like in your example.
However - things you should consider in your design:
Do I need my map to be Thread-Safe? if not, use a HashMap
Can you have the same rating for two cities? If not, maybe an array would be better?
If the answer to the above question is "yes" - do you need to get all the cities with the same rating? at which case you might need to come up with another data structure, or simply maintain two maps (one of City -> Rating and one of Rating -> City)
Is the rating OK with being a String - wouldn't you prefer an Integer so you can compare them?
Also, a few notes not related to the "design" of this question:
Prefer declaring the interface of the Collection you use instead of the implementation - it makes code changes easier and makes your API more robust.
Use generics - it makes code type safe and easier to read. e.g. Map<String, Integer> cityRatings = new Hashtable<String, Integer>();
import java.util.*;
public class java_hashtable {
public static void ratingofcity() {
Hashtable<String, String> cityRating = new Hashtable<String, String>();
CityRating.put("New York", "8");
CityRating.put("Sandton", "9");
}
}
Hashtable is declared in a wrong way. The changes which I made must work now.