replace values in a String from a Hashtable in Java - java

My string looks like;
String values = "I am from UK, and you are from FR";
and my hashtable;
Hashtable countries = new Hashtable();
countries.put("United Kingdom", new String("UK"));
countries.put("France", new String("FR"));
What would be the most effective way to change the values in my string with the values from the hashtable accordingly. These are just 2 values to change, but in my case I will have 100+

I'm not sure there's a whole lot you can do to optimize this in a way which is worthwhile. Actually you can construct an FSM for custom replacements like that but it's probably more than you want to really do.
Map<String, String> countries = new HashMap<String, String>();
countries.put("United Kingdom", "UK");
countries.put("France", "FR");
for (Map.Entry<String, String> entry : countries.entrySet()) {
values.replace(entry.getKey(), entry.getValue());
}
A couple of notes:
Don't use Hashtable. Use a Map (interface) and HashMap (class) instead;
Declare your variable, parameter and return types, where applicable, as interfaces not concrete classes;
Assuming you're using Java 5, use generic type arguments for more readable code. In this case, Map<String, String>, etc; and
Don't use new String("UK"). There is no need.

Several thoughts. First of all: why use hashtable? hashmap is usually faster as hashtable is synchronized.
Then: why not use generics?
HashMap<String, String>
is much more expressive than just HashMap
Third: don't use new String("UK"), "UK" will do fine, you're creating the same string twice.
But to solve your problem, you probably want to turn the map around:
Map<String,String> countries = new HashMap<String, String>();
countries.put("UK", "United Kingdom");
countries.put("FR", "France");
Now if I understand you right you want to do something like this:
String values = "I am from UK, and you are from FR";
for(Map.Entry<String, String> entry : countries.entrySet()){
values = values.replace(entry.getKey(), entry.getValue());
}

Related

HashMap as Value in HashMap [duplicate]

This question already has answers here:
Java - Initialize a HashMap of HashMaps
(4 answers)
Closed 4 years ago.
How can I create a "multidimensional" HashMap with HashMaps as Value without initializing every HashMap like you see below?
HashMap<Integer, String> DenmarkBasic = new HashMap<Integer, String>();
DenmarkBasic.put(1, "http://website1.com/");
DenmarkBasic.put(2, "http://website2.com/");
HashMap<Integer, String> DenmarkMisc = new HashMap<Integer, String>();
DenmarkMisc.put(1, "http://website1.com/");
DenmarkMisc.put(2, "http://website2.com/");
HashMap<String, HashMap<Integer, String>> DenmarkPanel = new HashMap<String, HashMap<Integer, String>>();
DenmarkPanel.put("Basic", DenmarkBasic);
DenmarkPanel.put("Misc", DenmarkMisc);
HashMap<String, HashMap<String, HashMap<Integer, String>>> NordicCountry = new HashMap<String, HashMap<String, HashMap<Integer, String>>>();
NordicCountry.put("Denmark", DenmarkPanel);
NordicCountry.put("Sweden", SwedenPanel);
HashMap<String, HashMap<String, HashMap<String, HashMap<Integer, String>>>> Market = new HashMap<String, HashMap<String, HashMap<String, HashMap<Integer, String>>>>();
Market.put("Nordic", NordicCountry);
I just want to use a loop, because it would be too much Maps.
Don't do that!
Nesting hash maps makes your code very very complicated very very quickly. Just look at how long your type names are getting.
You should write the data in another format, like JSON, and then parse it.
Your JSON would look something like this:
{
"Market" : {
"Nordic": {
"Denmark": {
"Basic": ["website1.com", "website2.com"],
"Misc": ["website1.com", "website2.com"]
},
"Sweden": {
"Basic": ["website1.com", "website2.com"],
"Misc": ["website1.com", "website2.com"]
},
}
}
}
And then you use a JSON parser to parse it. For example, as shown in this answer, you can use org.json. To get the list of basic Denmark websites:
jsonObject
.getJSONObject("Market")
.getJSONObject("Nordic")
.getJSONObject("Denmark")
.getJSONArray("Basic")
There are also other libraries mentioned in that post. Find the one you like the most and use it!
It's generally a bad practice to create such nested structures (like map contains a map, or list containing maps, etc.), so Guava comes with new collections, you can find there things like multimap, multiset which will help you write better, safer and future-proof code. Try it out, such structures are availalbe in Guava and Apache Collections
https://github.com/google/guava/wiki/NewCollectionTypesExplained#multimap

Is it possible to instantiate a Map with a list of keys?

Usually, if I know beforehand all the keys of a map, I instantiate it like this:
List<String> someKeyList = getSomeList();
Map<String, Object> someMap = new HashMap<String, Object>(someKeyList.size());
for (String key : someKeyList) {
someMap.put(key, null);
}
Is there any way to do this directly without needing to iterate through the list? Something to the effect of:
new HashMap<String, Object>(someKeyList)
My first thought was to edit the map's keyset directly, but the operation is not supported. Is there other way I'm overlooking?
You can use Java 8 Streams :
Map<String,Object> someMap =
someKeyList.stream()
.collect(Collectors.toMap(k->k,k->null));
Note that if you want a specific Map implementation, you'll have to use a different toMap method, in which you can specify it.

How to save enum class in a HashMap?

Let us say we have following enums:
public enum AnimalImages {
TIGER,BEAR,WOLF;
}
public enum CarImages {
BMW,VW,AUDI;
}
Now I want to save these enum classes in a HashMap:
Map<String,Enum<?>> enumMap=new HashMap<String,Enum<?>>();
enumMap.put("AnimalImages",???????);
What I should enter instead of the question marks?
To explicitly answer to your question, you have to put the enum value as this:
Map<String,Enum<?>> enumMap=new HashMap<String,Enum<?>>();
enumMap.put("AnimalImages", AnimalImages.TIGER);
However, if you want to put all the value belonging to an enum, then you could leverage values() method and also change your map to Map<String,Enum<?>[]> so you can use this:
Map<String,Enum<?>[]> enumMap=new HashMap<String,Enum<?>[]>(); // Note Enum<?>[] array
enumMap.put("AnimalImages", AnimalImages.values());
enumMap.put("CarImages", CarImages.values());
Another approach, with a shorten signature can be something like this:
Map<String, Object> enumMap = new HashMap<String,Object>();
enumMap.put("AnimalImages", AnimalImages.values());
enumMap.put("CarImages", CarImages.values());
Another way that bali182 pointed in this comment, you could use:
Map<String, Collection<? extends Enum<?>>> enumMap = new HashMap<>();
enumMap.put("AnimalImages", Arrays.asList(AnimalImages.values()));
enumMap.put("CarImages", Arrays.asList(AnimalImages.values()));
To answer your question:
enumMap.put("AnimalImages", AnimalImages.WOLF);
enumMap.put("Cars", CarImages.AUDI);
But you can also do
Map<String, AnimalImages> enumMap = new HashMap<String, AnimalImages>();
And this way enumMap.get("AnimalImages"), and this way you won't have to type check and cast it.
If the requirement is to create a Map that contains all values of a given enum, I would use a mapping of String keys into EnumSet values:
Map<String, EnumSet<?>> enumMap = new HashMap<String, EnumSet<?>>();
enumMap.put("AnimalImages", EnumSet.allOf(AnimalImages.class));
enumMap.put("CarImages", EnumSet.allOf(CarImages.class));
for (Map.Entry<String, EnumSet<?>> e : enumMap.entrySet()) {
System.out.println(String.format("key: [%s], values: %s",
e.getKey(), e.getValue().toString()));
}
EnumSet is a specialized Set implementation, which is represented internally as a bit vector. Its sole purpose is to provide an efficient and easy way to store enums.

Concatenating two hashmaps without removing common entires from both the maps

I have two hashmaps, in particular vocabs of two languages say english and german.I would like to concatenate both these map to return a single map.I tried :
hashmap.putall()
But, removed some of the entries which are common in both maps and replace it by single entry only.But i want to keep both the vocabs intact just concatenate those. Is there any method to do it? if not any other way to do. I would prefer any methods in hashmap.
[EDIT]
To make more clear, lets see two maps
at the 500 um die 500
0 1 2 0 1 2
resutls into
at the 500 um die 500
0 1 2 3 4 5
You'll have to write your own custom "putAll()` method then. Something like this would work:
HashMap<String> both = new HashMap<String>(english);
for(String key : german.keySet()) {
if(english.containsKey(key)) {
both.put(key, english.get(key)+german.get(key));
}
}
This first copies the English HashMap. Then puts in all the German words, concatenating if there is a duplicate key. You might want some kind of separator character like a / in between so you can later extract the two.
There isn't anything like that in the Java main library itself, you will have to use something provided by third parties like Google Guava's Multimap, it does exactly what you want, or build something like this manually.
You can download the Guava library at the project's website. Using a multimap is the same as using a map, as in:
Multimap<String,String> both = new ArrayListMultimap <String,String>();
both.putAll( german );
both.putAll( english);
for ( Entry<String,String> entry : both.entrySet() ) {
System.out.printf( "%s -> %s%n", entry.getKey(), entry.getValue() );
}
This code will print all key-value pairs including the ones that are present on both maps. So, if you have me->me at both german and english they would be printed twice.
You cannot do that directly with any Map implementation, since in a map, each key is unique.
A possible workaround is to use Map<Key, List<Value>>, and then do the concatenation of your maps manually. The advantage of using a List for the concatenated map, is that it will be easy to retrieve each of the individual values without any extra fiddling.
Something like that would work:
public Map<Key, List<Value>> concat(Map<Key, Value> first, Map<Key, Value> second){
Map<Key, List<Value>> concat = new HashMap<Key, List<Value>>();
putMulti(first, concat);
putMulti(second, concat);
return concat;
}
private void putMulti(Map<Key, Value> content, Map<Key, List<Value>> dest){
for(Map.Entry<Key, Value> entry : content){
List<Value> vals = dest.get(entry.getKey());
if(vals == null){
vals = new ArrayList<Value>();
dest.put(entry.getKey(), vals);
}
vals.add(entry.getValue());
}
}
Similar to #tskuzzy's answer
Map<String, String> both = new HashMap<String, String>();
both.putAll(german);
both.putAll(english);
for (String e : english.keySet())
if (german.containsKey(e))
both.put(e, english.get(e) + german.get(e));
Slight improvisation of #tskuzzy and #Peter's answer here. Just define your own StrangeHashMap by extending HashMap.
public class StrangeHashMap extends HashMap<String, String> {
#Override
public String put(String key, String value) {
if(this.containsKey(key)) {
return super.put(key, super.get(key) + value);
} else {
return super.put(key, value);
}
}
}
You can use it as so:
Map<String, String> map1 = new HashMap<String, String>();
map1.put("key1", "Value1");
map1.put("key2", "Value2");
Map<String, String> map2 = new HashMap<String, String>();
map2.put("key1", "Value2");
map2.put("key3", "Value3");
Map<String, String> all = new StrangeHashMap();
all.putAll(map1);
all.putAll(map2);
System.out.println(all);
The above prints the below for me:
{key3=Value3, key2=Value2, key1=Value1Value2}
Given the new elements in the question, it seems that what you actually need to use is lists. In this case, you can just do:
List<String> english = ...;
List<String> german = ...;
List<String> concat = new ArrayList<String>(english.size() + german.size());
concat.addAll(english);
concat.addAll(german);
And there you are. You can still use concat.get(n) to retreive the value nth value in the concatenated list.

Define a map as constant in java

For my Android app I've the need of defining some keys in a single constant, and I think the best way to do it is using a map. But not sure whether that's really the way to go, and how to do it correctly. As I'm targeting Android, a Bundle may also be an option.
I have a list of keys like:
"h" = "http"
"f" = "ftp"
Basically the program is to read a QR code (to keep that code from growing too big I'm using super-short keys), gets those keys, and has to translate them to something useful, in my case a protocol.
I'm trying to define a constant called KEY_PROTOCOLS, I think this should be a Map, so later I can call something like KEY_PROTOCOLS.get("f") to get the protocol that belongs to key "f".
Other classes should also be able to import this constant, and use it. So this map has to be populated in the class right away.
How can I do this?
If the constant is shared by several classes, and if you want to make sure this map is not cleared or modified by some code, you'd better make it unmodifiable :
public static final Map<String, String> KEY_PROTOCOLS;
static {
Map<String, String> map = new HashMap<String, String>();
map.put("f", "ftp");
// ...
KEY_PROTOCOLS = Collections.unmodifiableMap(map);
}
Something like this:
private static final Map<String, String> KEY_PROTOCOLS = new HashMap<String, String>();
static{
KEY_PROTOCOLS.put("f", "ftp");
// More
}
Static Initialisers:
http://www.glenmccl.com/tip_003.htm
This would work.
static Map<String, String> map = new HashMap<String, String>();
static {
map.add("ftp", "ftp");
...
}
On android:
#SuppressWarnings("unchecked")
Pair<String,String>[] pre_ips=new Pair[]{new Pair<String,String>("173.194", "0"), new Pair<String,String>("74.125", "96")};
String ip_1_2,ip_3;
for (Pair<String,String> pre_ip:pre_ips)
{ip_1_2=pre_ip.first;
ip_3=pre_ip.second;
}

Categories

Resources