This question already has answers here:
Java Equivalent to Python Dictionaries
(4 answers)
Closed 6 years ago.
I have a Dictionary in Python say
{ SERVER1 : [ (list1),(list2),....
SERVER2 : [ (list2a),(list2b) ] }
Is it same can be implemented in Java ?
I need to check each key if exist then I need to add the list to that key like appending the existing value without overriding
Also need to read the key and value and traverse through each value of list
Kindly assist. Sorry to ask these question as it is my first program in Java
In java, dictionaries are defined with the Map interface. The common implementations are TreeMap and HashMap:
Map<String,List<String>> servers = new HashMap<>();
servers.put("SERVER1", new ArrayList<String>());
servers.get("SERVER1").add("list1");
servers.get("SERVER1").add("list2");
...
Similarly, ArrayList and LinkedList are common implementations of the List interface.
Because you want to save each value associated with a key, you need a HashMap that contains ArrayLists for values. This object should do what you need:
public class HashOfLists<K, V> {
HashMap<K, ArrayList<V>> map = new HashMap<>();
public ArrayList<V> get(K key) {
return map.get(key);
}
public void put(K key, V value) {
ArrayList<V> existingValues = get(key);
if (existingValues == null) existingValues = new ArrayList<>();
existingValues.add(value);
map.put(key, existingValues);
}
}
To use it you would do something a bit like this:
HashOfLists<String, String> servers = new HashOfLists<>();
servers.put("SERVER3", "PROCESS A");
servers.put("SERVER3", "PROCESS B");
//Getting a list containing "PROCESS A" and "PROCESS B"
ArrayList<String> processes = servers.get("SERVER3");
Related
This question already has answers here:
How do I efficiently iterate over each entry in a Java Map?
(46 answers)
Closed 4 years ago.
I need to iterate each value of a HashMap in my method but it gives me a syntax error at the for each loop
Library.java:12: error: for-each not applicable to expression type
for(String book : library){
^ required: array or java.lang.Iterable found: HashMap
This is the relevant code
public void getFinishedBooks(HashMap<String, Boolean> library)
{
if(library.size()<1)
{
System.out.println("Library is empty!");
}
else
{
for(String book : library)
{
if(library.get(book) ==true)
{
System.out.println(book);
}
}
}
}
You can iterate over the set of entries:
for (Entry<String, Boolean> book : library.entrySet()) {
if (book.getValue()) {
System.out.println(book.getKey());
}
}
Map.entrySet() returns a Set of entries (java.util.Map.Entry). Each entry contains a pair with a key and its value.
You have different ways to iterate over a Map
forEach from Java 8 (this is more efficient)
library.forEach((k, v) -> System.out.println(v));
forEach and Entry
for (library.Entry<String, Boolean> pair : library.entrySet()) {
System.out.println(pair.getValue());
}
forEach and keySet
for (String key : library.keySet()) {
System.out.println(library.get(key));
}
You can use entrySet().
Quote from https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html:
public Set> entrySet()
Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation, or through the setValue operation on a map entry returned by the iterator) the results of the iteration are undefined. The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll and clear operations. It does not support the add or addAll operations.
You can traverse using below code by java8:
Map<String, Boolean> library= new HashMap<>();
library.put("Book1",true);
library.put("Book2",true);
library.put("Book3",false);
library.forEach((key, value) -> {
if(value){
System.out.println("Book = " + value);
}
});
I have a map:
Map<String, List<Object>> dataMap;
Now i want to add new key value pairs to the map like below:
if(dataMap.contains(key)) {
List<Object> list = dataMap.get(key);
list.add(someNewObject);
dataMap.put(key, list);
} else {
List<Object> list = new ArrayList();
list.add(someNewObject)
dataMap.put(key, list);
}
How can i do this with Java8 functional style?
You can use computeIfAbsent.
If the mapping is not present, just create one by associating the key with a new empty list, and then add the value into it.
dataMap.computeIfAbsent(key, k -> new ArrayList<>()).add(someNewObject);
As the documentation states, it returns the current (existing or computed) value associated with the specified key so you can chain the call with ArrayList#add. Of course this assume that the values in the original map are not fixed-size lists (I don't know how you filled it)...
By the way, if you have access to the original data source, I would grab the stream from it and use Collectors.groupingBy directly.
This can be simplified by using the ternary operator. You don't really need the if-else statement
List<Object> list = dataMap.containsKey(key) ? dataMap.get(key) : new ArrayList<>();
list.add(someNewObject);
dataMap.put(key, list);
You can also use compute method.
dataMap.compute(key, (k, v) -> {
if(v == null)
return new ArrayList<>();
else {
v.add(someNewObject);
return v;
}
});
you can use
dataMap.compute(key,(k,v)->v!=null?v:new ArrayList<>()).add(someNewObject)
or
dataMap.merge(key,new ArrayList<>(),(v1,v2)->v1!=null?v1:v2).add(someNewObject)
Based on the following code snippet :
Hashtable balance = new Hashtable();
Enumeration names;
String str;
double bal;
balance.put("Zara", new Double(3434.34)); //first entry for Zara
balance.put("Mahnaz", new Double(123.22));
balance.put("Zara", new Double(1378.00)); //second entry for Zara
balance.put("Daisy", new Double(99.22));
balance.put("Qadir", new Double(-19.08));
System.out.println(balance.entrySet());
.
Output : [Qadir=-19.08, Mahnaz=123.22, Daisy=99.22, Zara=1378.0]
Why isn't chaining happening here? When I re-enter with Zara as key the old value is overwritten. I expected it to be added at the end of the Linked List at Zara".hashcode() index.
Does Java use separate chaining only for collision handling?
If I can't use chaining( as I'v tried above) please suggest a common method to do so.
Does Java use separate chaining only for collision handling?
Yes. You can only have one entry per key in a Hashtable (or HashMap, which is what you should probably be using - along with generics). It's a key/value map, not a key/multiple-values map. In the context of a hash table, the term "collision" is usually used for the situation where two unequal keys have the same hash code. They still need to be treated as different keys, so the implementation has to cope with that. That's not the situation you're in.
It sounds like you might want a multi-map, such as one of the ones in Guava. You can then ask a multimap for all values associated with a particular key.
EDIT: If you want to build your own sort of multimap, you'd have something like:
// Warning: completely untested
public final class Multimap<K, V> {
private final Map<K, List<V>> map = new HashMap<>();
public void add(K key, V value) {
List<V> list = map.get(key);
if (list == null) {
list = new ArrayList();
map.put(key, list);
}
list.add(value);
}
public Iterable<V> getValues(K key) {
List<V> list = map.get(key);
return list == null ? Collections.<V>emptyList()
: Collections.unmodifiableList(list);
}
}
Quote from the documentation of Map (which Hashtable is an implementation of):
An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.
(emphasis mine)
The documentation of put() also says:
If the map previously contained a mapping for the key, the old value is replaced by the specified value
So if you want multiple values associated with a key, use a Map<String, List<Double>> instead of a Map<String, Double>. Guava also has a Multimap, which does what you want without having to deal with Lists explicitely as with a Map<String, List<Double>>.
This question already has answers here:
Map implementation with duplicate keys
(20 answers)
Closed 9 years ago.
Is there a native data structure in java that accepts key value pairs and allows duplicates? I am creating a checklist of characters in a string but some characters occur more than once.
ex
j -> false
a -> false
v -> false
a -> false
You can simulate multiple key-value (KV) pairs by saving a list of values for each in a map. This is a standard implementation approach for "multivalue" maps.
So, if the key is a Character object and the value is Boolean, you can do
Map<Character, List<Boolean>> multimap = new HashMap<Character, List<Boolean>>();
and every time you want to add a new value to an existing KV pair in the map just call
multimap.get(key).add(value);
where key is the Character and value its corresponding Boolean value.
The Guava library by Google (free download) has a Multimap interface implemented in various ways, so essentially you can instantiate a MultiMap<Character, Boolean> map and use it accordingly. Similarly, you can get the Apache Commons Collections library and use its MultiValueMap class. You may also want to check the answers to a similar StackOverflow question, or another one.
If you only want to store one of each value per key, then a Set should be used in the place of the List.
Use a List of Pairs:
public class Pair<T, U> {
public final T key;
public final U value;
public Pair(T key, U value) {
this.key = key;
this.value = value;
}
}
public class YourApp {
public static void main(String[] args) {
List<Pair<Character, Boolean>> charList = new ArrayList<Pair<Character, Boolean>>();
charList.add(new Pair('j', false));
charList.add(new Pair('a', false));
charList.add(new Pair('v', false));
charList.add(new Pair('a', false));
for (Pair<Character, Boolean> pair : charList) {
System.out.println(pair.key + " -> " + pair.value);
}
}
}
With the selfwritten generic Pair class you can hold a key and a value of any type you want. If you're adding pairs to a List, you can even hold duplicates of pair entries.
You can use MultiMap<Character,Boolean> bcoz it allows duplicate key which exist in org.apache.commons.collections package.
or
You can use ArrayList and add the objects of the Class that contain attribute as char & boolean pair.
I do not know of a build in solution.
A quick alternative would be to use a simple ArrayList, and create an object that is a char/boolean pair that you can add to it.
commons.apache.org have MultiHashMap class. Try this one...!!!
MultiHashMap mp = new MultiHashMap();
mp.put("a", "1");
mp.put("b", "4");
mp.put("c", "2");
mp.put("a", "6");
List list = null;
Set set = mp.entrySet();
Iterator i = set.iterator();
while (i.hasNext()) {
Map.Entry<String, List<String>> me = (Map.Entry) i.next();
for(int j = 0 ; j< me.getValue().size(); j++ ){
System.out.println(me.getKey() +" : " +me.getValue().get(j));
}
}
}
I have a HashMap as below (assuming it has 10,0000 elements)
HashMap<String,String> hm = new HashMap<String,String>();
hm.put("John","1");
hm.put("Alex","2");
hm.put("Mike","3");
hm.put("Justin","4");
hm.put("Code","5");
==========================
Expected Output
==========================
Key = John",Value = "1"
Key = Alex",Value = "2"
Key = Mike",Value = "3"
Key = Justin",Value = "4"
Key = Code",Value = "5"
===========================
I need Java code to prevent Addition of Duplicate <Key,Value> Pairs in HashMap such
that below conditions are staisfied.
1> hm.put("John","1"); is not accepted/added again in the Map
2> hm.put("John","2"); is not accepted/added again in the Map
Hope its clear.
Java code provided will be appreciated.(generic solution needed since i can add any duplicate to the existing map)
You can wrap HashMap in a class, which delegates put, get, and other methods you use from HashMap. This method is wasteful but safe, since it doesn't depend on the internal implementation of HashMap, AbstractMap. The code below illustrates put, get delegating:
public class Table {
protected java.util.HashMap<String, Integer> map =
new java.util.HashMap<String, Integer>();
public Integer get(String key) { return map.get(key); }
public Integer put(String key, Integer value) {
if (map.containsKey(key)) {
// implement the logic you need here.
// You might want to return `value` to indicate
// that no changes applied
return value;
} else {
return map.put(key, value);
}
}
// other methods goes here
}
Another option is to make a class which extends HashMap, and depend on its internal implementation. Java 1.6 sources shows that put is called only in putAll in HashMap, so you can simply override put method:
public class Table extends java.util.HashMap<String, Integer> {
public Integer put(String key, Integer value) {
if (containsKey(key)) {
// implement the logic you need here.
// You might want to return `value` to indicate
// that no changes applied
return value;
} else {
return super.put(key, value);
}
}
}
Another option is similar to the first, and can make an utility method in your class which contains the HashMap instance and call that method wherever you need put something to your map:
public final Integer putToMap(String key, String value) {
if(this.map.containsKey(key)) {
return value;
} else {
return this.map.put(key, value);
}
}
This is an "inline" equivalent of checking manually.
I note that you clarify the question by suggesting you might have "100000000 elements". You still won't have duplicates in the HashMap, because, as two other posters have pointed out, you can't get duplicate keys in a Map. I'm still not sure we understand the question, though, as it's not at all clear how you expected to generate the block titled "Output", or what you intend to do with it.
This may be old question but I thought to share my experience with this. As others pointed out you can't have the same element in a HashMap. By default HashMap will not allow this but there are some cases that you could end up with two or more elements are almost alike that you do not accept but HashMap will. For example, the following code defines a HashMap that takes an array of integers as a key then add :
HashMap<int[], Integer> map1 = new HashMap<>();
int[] arr = new int[]{1,2,3};
map1.put(arr, 4);
map1.put(arr, 4);
map1.put(arr, 4);
At this point, the HashMap did not allow dublicating the key and map1.size() will return 1. However, if you added elements without creating the array first things will be different:
HashMap<int[], Integer> map2 = new HashMap<>();
map2.put(new int[]{4,5,6}, 6);
map2.put(new int[]{4,5,6}, 6);
map2.put(new int[]{4,5,6}, 6);
This way, the HashMap will add all the three new elements so the map2.size() will return 3 and not 1 as expected.
The explanation is that with the first map I created the object arr once and tried to add the same object 3 times which HashMap does not allow by default so only the last usage will be considered. With the second map, however, evey time I recreate a new object on the stack. The three objects created are different and separated thought the three of them have the same data but they are different. That's why HashMap allowed them as different keys.
Bottom line, you don't need to prevent HashMap from adding dublicated keys because it won't by design. However, you have to watch out how you define these keys because the fault may be on your side.
List<String> keys = new ArrayList<String>(); (1000000)
List<String> values = new ArrayList<String>(); (1000000)
Map<String, String> map = new HashMap<String, String>();
int i =0;
for(String key : keys){
String returnedValue = map.put(key, values.get(i));
if(returnedValue!=null){
map.put(key, returnedValue);
system.out.println("Duplicate key trying to be entered with new value so reverting the duplicate key ="+key+"new Value"+values.get(i));
}
}
Unfortunately, it is the way that Map works.
The easiest workaround is to remove all pre existed keys and their values by calling hm.remove() first! like this:
for (String name : names) {
hm.remove(name);
hm.put(name,uri.getQueryParameter(name));
}
And if you don't use a for loop just call it like this:
hm.remove("John");
hm.put("John","1");
hm.remove("Alex");
hm.put("Alex","2");
hm.remove("Mike");
hm.put("Mike","3");
And so on ...
see even if u write same key values multiple times you will just have unique set of pairs. Check that by either iterating or by doing hm.size();
if(hm.put("John","1") != null)
{
// "John" was already a key in the map. The sole value for this key is now "1".
}
List<Object> yourElements = new ... // 10000000
for(Object O : yourElements) {
if(myMap.get(O.key)==null) {
myMap.put(O.key,O);
}
}