public Map mystery(Map map1, Map map2) {
Map result = new TreeMap();
for (String s1 : map1.keySet()) {
if (map2.containsKey(map1.get(s1))) {
result.put(s1, map2.get(map1.get(s1)));
}
}
return result;
}
map1={bar=1, baz=2, foo=3, mumble=4}; map2={1=earth, 2=wind, 3=air, 4=fire}
For each key in map1 method looks at the corresponding value and of this value exists as a key in map2 than puts it a new TreeMap.
Consider one iteration. map1 has key bar and it's value is 1. Now map2 has 1 as it's key with value earth. So data that is put in new Map is bar:earth and so on..
Also note since resultant map is a TreeMap elements will be stored in Lexicographical order (Since keys are Strings and TreeMap stores elements in sorted order as per keys natural ordering).
It's calculating the composition of the functions map2(map1), along with giving you an impressive number of raw-type warnings.
Related
I am having an arraylist which contains a list of numbers. I want to get all the values from the HashMap which has the keys which are in the array list.
For example say the array list contains 1,2,3,4,5,6,7,8,9 list
I want to get all the values for the keys 1,2,3,4,5,6,7,8,9 map
So currently I am implementing
for (i=0;i<list.size;i++){
map_new.put(list.get(),map.get(list.get()))
}
Is there any efficient way to do this?
Your code basically assumes that map.get(list.get()) always returns a value, you can try the following code which first filters the not null values from the list object and then adds to the new Map:
Map<String, Integer> newMap = list.stream().
filter(key -> (map.get(key) != null)).//filter values not present in Map
collect(Collectors.toMap(t -> t, t -> map.get(t)));//now collect to a new Map
In case, if map.get(list.get()) returns null, your code creates a Map with null values in it for which you might end up doing null checks, which is not good, rather you can ensure that your newly created Map always contains a value for each key.
Assuming the signature of list and the map are as following
List<Integer> list;
Map<Integer, Integer> map;
You can use following
for(int a : list){
Integer b = map.get(a);
if(b != null)
// b is your desired value you can store in another collection
}
Which is similar to the procedure you have already used.
As you can access the map in O(1) so the complexity of this code will be O(listsize)
There is not much you can do for efficiency. Still couple of small things you can do considering code example you have given above:
1) Change your for loop to
for(Long num : list)
instead of iterating using index, this will reduce you get calls over list.
2) You can update the existing map , so that you even do not need to iterate.
map.keySet().retainAll(list);
for(Long key: map.keySet()) {
System.out.println(map.get(key));
}
With this existing map will contain only those data whose keys are present in list, but you should use it carefully depending upon rest of the code logic.
You can capitalize on the fact that the keyset of a map is backed by the map itself and modifications to the keyset will reflect back to the map itself. This way, you can use the retainAll() method of the Set interface to reduce the map with a single line of code. Here is an example:
final Map<Integer, String> m = new HashMap<Integer, String>();
m.put(1, "A");
m.put(2, "B");
m.put(3, "C");
m.put(4, "D");
m.put(5, "E");
final List<Integer> al = Arrays.asList(new Integer[] { 2, 4, 5 });
System.out.println(m);
m.keySet().retainAll(al);
System.out.println(m);
This will output:
{1=A, 2=B, 3=C, 4=D, 5=E}
{2=B, 4=D, 5=E}
I want to determine if a given String startsWith any key in a Map.
The simple solution is to iterate through entire the keySet.
private static Map<String, String> someMap;
private static void method(String line) {
for (String key : someMap.keySet()) {
if (line.startsWith(key)) {
// do something with someMap.get(key);
}
}
}
My question is: Is there is a better data structure to handle this problem?
This can't be done directly with an HashMap: the problem is that HashMap uses an hash calculated on the key to manage its position inside the collection. So there is no way to search for a String key which starts with a specific substring since there is no correlation between two similar String values and their hashes.
But nothing is lost, if you switch to a TreeMap<String,String> the problem can be solved easily. A TreeMap is still an associative container but it stores entries by using a red-black tree in a sorted order.
This means that elements inside a TreeMap are always sorted. In addition to this it gives you some functionalities like:
Map.Entry<K,V> ceilingEntry(K key): Returns a key-value mapping associated with the least key greater than or equal to the given key, or null if there is no such key.
Map.Entry<K,V> floorEntry(K key): Returns a key-value mapping associated with the greatest key less than or equal to the given key, or null if there is no such key.
Now, not only you can search for a specific key by using a substring of its value, but you also do it in an efficient way. Mind that this works thanks to the implementation of compareTo of String class.
So your problem becomes trivial:
TreeMap<String, Object> map = new TreeMap<String, Object>();
map.put("baz", new Object());
map.put("foo", new Object());
map.put("fooz", new Object());
map.put("fo", new Object());
Map.Entry<String, Object> test = map.ceilingEntry("fo");
bool containsSubStringKey = test != null && test.getKey().startsWith("fo");
TreeMap<String, Object> map = new TreeMap<String, Object>();
map.put("baz", new Object());
map.put("foo", new Object());
map.put("fooz", new Object());
map.put("foor", new Object());
NavigableMap tempMap = list.subMap("foo", true, "fop", false);
//This will return a map of keys that start with "foo". true means inclusive and //false exclusive. "fop" is the first key that does not start with "foo"
I'm new to HashMap in java. I'm trying to create a situation where collision takes place and for same key (1 in this case). I read that the values in HashMap are not over written, instead, they are maintained in a link list. How to display all the values of key "1"?
public static void main(String[] args)
{
HashMap<String, String> hash = new HashMap<String, String>();
hash.put("1", "one");
hash.put("1", "two");
hash.put("1", "three");
hash.put("1", "four");
System.out.println(hash);
}
The output of the above code -
{1=two}
That's not true. Only one key,value pair for each unique key is stored in the map. The latest value you put in the map for a specific key would override the previous value that was stored for that key.
Different keys might have the same hash code, which causes them to be stored in the same linked list inside the HashMap, but the keys in the map are all unique. For each two keys in the map key1.equals(key2) would return false, even if key1.hashCode()==key2.hashCode().
The first 2 lines of Map javadoc explains it all.
public interface Map<K,V>
An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.
The javadoc for Map can be found here - http://docs.oracle.com/javase/7/docs/api/java/util/Map.html
Map<String, String> map = new HashMap<String, String>();
map.put("1", "xyz");
map.put("1", "abc");
map.put("1", "cde");
map.put("2", "err");`
`
for the above map I want to get all the values associated with the key 1. Expected output.
Key:: 1 values are:: xyz, abc, cde
Order of the values doesn't important.
In a Map the key should always be unique. If you associate a new value to an existing key, it will overwrite the value of the existing entry.
You might need to check the interface for Map#put(K, V) method.
If the map previously contained a mapping for the key, the old value
is replaced by the specified value.
So in your case your map will always have "cde" as the value for the key "1".
Use MultiMap
MultiMap mapValue = new MultiValueMap();
mapValue.put("1", "xyz");
mapValue.put("1", "abc");
mapValue.put("1", "cde");
mapValue.put("2", "err");
System.out.println("Map : " + mapValue);
Output: Map : {2=[err], 1=[xyz, abc, cde]}
A map can not have duplicate keys.
If you want to implement what you describe in question. First you need to use multimaps
What you are doing is wrong.
Map doesn't allow duplicates.
So one key -----------> one value
If you see docs of 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.)
You can print the values of each key and value like
Ex:
Map<String, String> map = new HashMap<String, String>();
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
In Map you can't have duplicate keys. so In your case final value put for key 1. "cde" will remain in Map
You can do some thing like following to achive what you are expecting
Map<String, List<String>> map = new HashMap<>();
List<String> list=new ArrayList<>();
List<String> list1=new ArrayList<>();
list.add("xyz");
list.add("abc");
list.add("cde");
list1.add("err");
map.put("1", list);
map.put("2",list1);
System.out.println(map.get("1"));
HashMap::put overrides the old value associated with the key. You have to put a List in each map entry and insert new values in the appropriate list.
From the java documentation about HashMap.put(K key, V value) method:
Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.
So you can't do that.
This is impossible, a map is called a map because it maps one key value to a value. Multiple keys can map to the same value but not the other way around.
What you probably want is a map which maps to a List<String> instead:
final Map<String, List<String>> map = new HashMap<>();
if (map.get("1") == null) {
map.put("1", new ArrayList<String>());
}
map.get("1").add("xyz");
// ...
A helper function for adding might be convenient
public static <K, V> void add(final K key, final V value, final Map<K, List<V>> map)
{
if (map.get(key) == null) {
map.put(key, new ArrayList<V>());
}
map.get(key).add(value);
}
You can not do this with this type of Map. The key in map must be unique.
To be able to do that you should declare a map, where key is string but values are collections of Strings.
Map<String,Collection<String>> map = new HashMap<String,Collection<String>>();
The to list values from it you can do this
for(String valueOfKey : map.get("key") {
//print or something else
}
Note that to add some values to it you must first check that key is already stored and if not then fist declare a collection.
if(map.contains("key") == false) {
map.put(new ArrayList<String>());
}
map.get("key").add("value");
As this is well know design you might be interest in guava framework and Multimap
The benefit of this class is that it already has implemented the logic how to add and retrieve values from it.
You could do something like:
for (String k : map.keySet())
System.out.println(k);
This would print the keys in the HashMap, but without any guarantees on order.
You can not have duplicate key for a hash map see the below S.O for What happens for duplicate keys in HashMap
I have a Map<String,String> which has entries like "User1","43". Now I want a "Top 3" of the highest values.
It would be easier with a Map<String,Integer>, but due to technical limitations I can just grab the Map as a <String,String>.
What's the most efficient way to convert a <String,String> map to a <String,Int> one and then sort it?
To convert from <String, String> to <String, Integer> you can use:
Map<String, Integer> treemap = new HashMap<String, Integer>();
for (Entry<String, String> entry : entries) {
treemap.put(entry.getKey(), Integer.parseInt(entry.getValue()));
}
However, then you will have to iterate the Map again. If you don't need the whole map, but rather just the top 3, then you can simply iterate the entries and get the top three by comparison.
Or you can reverse the key and value and use a TreeMap<Integer, String> with a Comparator, if you need both the top elements and the whole data.
There are a few ways:
Create SortedMap, e.g. TreeMap with a custom -anonymous- Comparator which performs comparisons by looking up the keys it gets in the compare() method call against the values in the original map.
Populate it with all key/value entries in the original through addAll() method.
Watch the map being sorted by value.
Grab the head/tail (depending on how your comparator sorts)
Similar to above:
Create a TreeSet of keys with a custom comparator as above...
Populate it with the keySet() of your original map.
Grab the head/tail set of the keys.
Create a new Map from those keys and value from the original map...
You could just put the values in a List and sort it:
ArrayList<Integer> highest = new ArrayList<Integer>();
for (String value : map.values()) {
highest.add(Integer.parseInt(value));
}
Collections.sort(highest);
for(int i = highest.size() - 1; i >=0 && i > highest.size()-4; i--){
System.out.println(highest.get(i));
}
If the map is very large it might be better to iterate through it and only select the 3 highest values without sorting the whole list.
You could iterate through the values of the Map (with Map.values()), converting each to an Integer (with Integer.getInteger(String s)), and keeping track of the top 3 you see.
Or, you could do as above but instead of keeping track of the top 3, make a LinkedList and insert each Integer at the correct place (traverse the LinkedList until you find where the Integer should be inserted).