Is it possible for us to implement a HashMap with one key and two values. Just as HashMap?
Please do help me, also by telling (if there is no way) any other way to implement the storage of three values with one as the key?
You could:
Use a map that has a list as the value. Map<KeyType, List<ValueType>>.
Create a new wrapper class and place instances of this wrapper in the map. Map<KeyType, WrapperType>.
Use a tuple like class (saves creating lots of wrappers). Map<KeyType, Tuple<Value1Type, Value2Type>>.
Use mulitple maps side-by-side.
Examples
1. Map with list as the value
// create our map
Map<String, List<Person>> peopleByForename = new HashMap<>();
// populate it
List<Person> people = new ArrayList<>();
people.add(new Person("Bob Smith"));
people.add(new Person("Bob Jones"));
peopleByForename.put("Bob", people);
// read from it
List<Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs[0];
Person bob2 = bobs[1];
The disadvantage with this approach is that the list is not bound to exactly two values.
2. Using wrapper class
// define our wrapper
class Wrapper {
public Wrapper(Person person1, Person person2) {
this.person1 = person1;
this.person2 = person2;
}
public Person getPerson1() { return this.person1; }
public Person getPerson2() { return this.person2; }
private Person person1;
private Person person2;
}
// create our map
Map<String, Wrapper> peopleByForename = new HashMap<>();
// populate it
peopleByForename.put("Bob", new Wrapper(new Person("Bob Smith"),
new Person("Bob Jones"));
// read from it
Wrapper bobs = peopleByForename.get("Bob");
Person bob1 = bobs.getPerson1();
Person bob2 = bobs.getPerson2();
The disadvantage to this approach is that you have to write a lot of boiler-plate code for all of these very simple container classes.
3. Using a tuple
// you'll have to write or download a Tuple class in Java, (.NET ships with one)
// create our map
Map<String, Tuple2<Person, Person> peopleByForename = new HashMap<>();
// populate it
peopleByForename.put("Bob", new Tuple2(new Person("Bob Smith",
new Person("Bob Jones"));
// read from it
Tuple<Person, Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs.Item1;
Person bob2 = bobs.Item2;
This is the best solution in my opinion.
4. Multiple maps
// create our maps
Map<String, Person> firstPersonByForename = new HashMap<>();
Map<String, Person> secondPersonByForename = new HashMap<>();
// populate them
firstPersonByForename.put("Bob", new Person("Bob Smith"));
secondPersonByForename.put("Bob", new Person("Bob Jones"));
// read from them
Person bob1 = firstPersonByForename["Bob"];
Person bob2 = secondPersonByForename["Bob"];
The disadvantage of this solution is that it's not obvious that the two maps are related, a programmatic error could see the two maps get out of sync.
No, not just as a HashMap. You'd basically need a HashMap from a key to a collection of values.
If you're happy to use external libraries, Guava has exactly this concept in Multimap with implementations such as ArrayListMultimap, HashMultimap, LinkedHashMultimap etc.
Multimap<String, Integer> nameToNumbers = HashMultimap.create();
System.out.println(nameToNumbers.put("Ann", 5)); // true
System.out.println(nameToNumbers.put("Ann", 5)); // false
nameToNumbers.put("Ann", 6);
nameToNumbers.put("Sam", 7);
System.out.println(nameToNumbers.size()); // 3
System.out.println(nameToNumbers.keySet().size()); // 2
Another nice choice is to use MultiValuedMap from Apache Commons. Take a look at the All Known Implementing Classes at the top of the page for specialized implementations.
Example:
HashMap<K, ArrayList<String>> map = new HashMap<K, ArrayList<String>>()
could be replaced with
MultiValuedMap<K, String> map = new MultiValuedHashMap<K, String>();
So,
map.put(key, "A");
map.put(key, "B");
map.put(key, "C");
Collection<String> coll = map.get(key);
would result in collection coll containing "A", "B", and "C".
Take a look at Multimap from the guava-libraries and its implementation - HashMultimap
A collection similar to a Map, but which may associate multiple values with a single key. If you call put(K, V) twice, with the same key but different values, the multimap contains mappings from the key to both values.
I use Map<KeyType, Object[]> for associating multiple values with a key in a Map. This way, I can store multiple values of different types associated with a key. You have to take care by maintaining proper order of inserting and retrieving from Object[].
Example:
Consider, we want to store Student information. Key is id, while we would like to store name, address and email associated to the student.
//To make entry into Map
Map<Integer, String[]> studenMap = new HashMap<Integer, String[]>();
String[] studentInformationArray = new String[]{"name", "address", "email"};
int studenId = 1;
studenMap.put(studenId, studentInformationArray);
//To retrieve values from Map
String name = studenMap.get(studenId)[1];
String address = studenMap.get(studenId)[2];
String email = studenMap.get(studenId)[3];
HashMap<Integer,ArrayList<String>> map = new HashMap<Integer,ArrayList<String>>();
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
list.add("xyz");
map.put(100,list);
If you use Spring Framework. There is: org.springframework.util.MultiValueMap.
To create unmodifiable multi value map:
Map<String,List<String>> map = ...
MultiValueMap<String, String> multiValueMap = CollectionUtils.toMultiValueMap(map);
Or use org.springframework.util.LinkedMultiValueMap
The easiest way would be to use a google collection library:
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
public class Test {
public static void main(final String[] args) {
// multimap can handle one key with a list of values
final Multimap<String, String> cars = ArrayListMultimap.create();
cars.put("Nissan", "Qashqai");
cars.put("Nissan", "Juke");
cars.put("Bmw", "M3");
cars.put("Bmw", "330E");
cars.put("Bmw", "X6");
cars.put("Bmw", "X5");
cars.get("Bmw").forEach(System.out::println);
// It will print the:
// M3
// 330E
// X6
// X5
}
}
maven link: https://mvnrepository.com/artifact/com.google.collections/google-collections/1.0-rc2
more on this: http://tomjefferys.blogspot.be/2011/09/multimaps-google-guava.html
Just for the record, the pure JDK8 solution would be to use Map::compute method:
map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);
Such as
public static void main(String[] args) {
Map<String, List<String>> map = new HashMap<>();
put(map, "first", "hello");
put(map, "first", "foo");
put(map, "bar", "foo");
put(map, "first", "hello");
map.forEach((s, strings) -> {
System.out.print(s + ": ");
System.out.println(strings.stream().collect(Collectors.joining(", ")));
});
}
private static <KEY, VALUE> void put(Map<KEY, List<VALUE>> map, KEY key, VALUE value) {
map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);
}
with output:
bar: foo
first: hello, foo, hello
Note that to ensure consistency in case multiple threads access this data structure, ConcurrentHashMap and CopyOnWriteArrayList for instance need to be used.
Yes and no. The solution is to build a Wrapper clas for your values that contains the 2 (3, or more) values that correspond to your key.
Yes, this is frequently called a multimap.
See: http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/collect/Multimap.html
Using Java Collectors
// Group employees by department
Map<Department, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
where Department is your key
String key= "services_servicename"
ArrayList<String> data;
for(int i = 0; i lessthen data.size(); i++) {
HashMap<String, String> servicesNameHashmap = new HashMap<String, String>();
servicesNameHashmap.put(key,data.get(i).getServiceName());
mServiceNameArray.add(i,servicesNameHashmap);
}
I have got the Best Results.
You just have to create new HashMap like
HashMap<String, String> servicesNameHashmap = new HashMap<String, String>();
in your for loop. It will have same effect like same key and multiple values.
import java.io.*;
import java.util.*;
import com.google.common.collect.*;
class finTech{
public static void main(String args[]){
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("1","11");
multimap.put("1","14");
multimap.put("1","12");
multimap.put("1","13");
multimap.put("11","111");
multimap.put("12","121");
System.out.println(multimap);
System.out.println(multimap.get("11"));
}
}
Output:
{"1"=["11","12","13","14"],"11"=["111"],"12"=["121"]}
["111"]
This is Google-Guava library for utility functionalities. This is the required solution.
I could not post a reply on Paul's comment so I am creating new comment for Vidhya here:
Wrapper will be a SuperClass for the two classes which we want to store as a value.
and inside wrapper class, we can put the associations as the instance variable objects for the two class objects.
e.g.
class MyWrapper {
Class1 class1obj = new Class1();
Class2 class2obj = new Class2();
...
}
and in HashMap we can put in this way,
Map<KeyObject, WrapperObject>
WrapperObj will have class variables: class1Obj, class2Obj
You can do it implicitly.
// Create the map. There is no restriction to the size that the array String can have
HashMap<Integer, String[]> map = new HashMap<Integer, String[]>();
//initialize a key chosing the array of String you want for your values
map.put(1, new String[] { "name1", "name2" });
//edit value of a key
map.get(1)[0] = "othername";
This is very simple and effective.
If you want values of diferent classes instead, you can do the following:
HashMap<Integer, Object[]> map = new HashMap<Integer, Object[]>();
Can be done using an identityHashMap, subjected to the condition that the keys comparison will be done by == operator and not equals().
I prefer the following to store any number of variables without having to create a separate class.
final public static Map<String, Map<String, Float>> myMap = new HashMap<String, Map<String, Float>>();
I am so used to just doing this with a Data Dictionary in Objective C. It was harder to get a similar result in Java for Android. I ended up creating a custom class, and then just doing a hashmap of my custom class.
public class Test1 {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addview);
//create the datastring
HashMap<Integer, myClass> hm = new HashMap<Integer, myClass>();
hm.put(1, new myClass("Car", "Small", 3000));
hm.put(2, new myClass("Truck", "Large", 4000));
hm.put(3, new myClass("Motorcycle", "Small", 1000));
//pull the datastring back for a specific item.
//also can edit the data using the set methods. this just shows getting it for display.
myClass test1 = hm.get(1);
String testitem = test1.getItem();
int testprice = test1.getPrice();
Log.i("Class Info Example",testitem+Integer.toString(testprice));
}
}
//custom class. You could make it public to use on several activities, or just include in the activity if using only here
class myClass{
private String item;
private String type;
private int price;
public myClass(String itm, String ty, int pr){
this.item = itm;
this.price = pr;
this.type = ty;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public String getType() {
return item;
}
public void setType(String type) {
this.type = type;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
We can create a class to have multiple keys or values and the object of this class can be used as a parameter in map.
You can refer to https://stackoverflow.com/a/44181931/8065321
Apache Commons collection classes can implement multiple values under same key.
MultiMap multiMapDemo = new MultiValueMap();
multiMapDemo .put("fruit", "Mango");
multiMapDemo .put("fruit", "Orange");
multiMapDemo.put("fruit", "Blueberry");
System.out.println(multiMapDemo.get("fruit"));
Maven Dependency
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
Related
How I can get the third value for the first key in this map? Is this possible?
Libraries exist to do this, but the simplest plain Java way is to create a Map of List like this:
Map<Object,ArrayList<Object>> multiMap = new HashMap<>();
It sounds like you're looking for a multimap. Guava has various Multimap implementations, usually created via the Multimaps class.
I would suggest that using that implementation is likely to be simpler than rolling your own, working out what the API should look like, carefully checking for an existing list when adding a value etc. If your situation has a particular aversion to third party libraries it may be worth doing that, but otherwise Guava is a fabulous library which will probably help you with other code too :)
For example:
Map<Object,Pair<Integer,String>> multiMap = new HashMap<Object,Pair<Integer,String>>();
where the Pair is a parametric class
public class Pair<A, B> {
A first = null;
B second = null;
Pair(A first, B second) {
this.first = first;
this.second = second;
}
public A getFirst() {
return first;
}
public void setFirst(A first) {
this.first = first;
}
public B getSecond() {
return second;
}
public void setSecond(B second) {
this.second = second;
}
}
This is what i found in a similar question's answer
Map<String, List<String>> hm = new HashMap<String, List<String>>();
List<String> values = new ArrayList<String>();
values.add("Value 1");
values.add("Value 2");
hm.put("Key1", values);
// to get the arraylist
System.out.println(hm.get("key1"));
RESULT: [Value 1, Value 2]
A standard Java HashMap cannot store multiple values per key, any new entry you add will overwrite the previous one.
Have you got something like this?
HashMap<String, ArrayList<String>>
If so, you can iterate through your ArrayList and get the item you like with arrayList.get(i).
I found the blog on random search, i think this will help for doing this: http://tomjefferys.blogspot.com.tr/2011/09/multimaps-google-guava.html
public class MutliMapTest {
public static void main(String... args) {
Multimap<String, String> myMultimap = ArrayListMultimap.create();
// Adding some key/value
myMultimap.put("Fruits", "Bannana");
myMultimap.put("Fruits", "Apple");
myMultimap.put("Fruits", "Pear");
myMultimap.put("Vegetables", "Carrot");
// Getting the size
int size = myMultimap.size();
System.out.println(size); // 4
// Getting values
Collection<String> fruits = myMultimap.get("Fruits");
System.out.println(fruits); // [Bannana, Apple, Pear]
Collection<string> vegetables = myMultimap.get("Vegetables");
System.out.println(vegetables); // [Carrot]
// Iterating over entire Mutlimap
for(String value : myMultimap.values()) {
System.out.println(value);
}
// Removing a single value
myMultimap.remove("Fruits","Pear");
System.out.println(myMultimap.get("Fruits")); // [Bannana, Pear]
// Remove all values for a key
myMultimap.removeAll("Fruits");
System.out.println(myMultimap.get("Fruits")); // [] (Empty Collection!)
}
}
Try using collections to store the values of a key:
Map<Key, Collection<Value>>
you have to maintain the value list yourself
Apache Commons collection classes is the solution.
MultiMap multiMapDemo = new MultiValueMap();
multiMapDemo .put("fruit", "Mango");
multiMapDemo .put("fruit", "Orange");
multiMapDemo.put("fruit", "Blueberry");
System.out.println(multiMap.get("fruit"));
// Mango Orange Blueberry
Maven Dependency
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 --
>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
Apart from all the answers here, I have a solution that I used and found it most useful if you know the length of multiple values to be added to your key.
In my case, it was 2, so I opted for this over a List<string>.
HashMap<String, String[]> multimap= new HashMap<>();
multimap.put("my_key", new String[]{"my_value1", "my_value2"});
Thinking about a Map with 2 keys immediately compelled me to use a user-defined key, and that would probably be a Class. Following is the key Class:
public class MapKey {
private Object key1;
private Object key2;
public Object getKey1() {
return key1;
}
public void setKey1(Object key1) {
this.key1 = key1;
}
public Object getKey2() {
return key2;
}
public void setKey2(Object key2) {
this.key2 = key2;
}
}
// Create first map entry with key <A,B>.
MapKey mapKey1 = new MapKey();
mapKey1.setKey1("A");
mapKey1.setKey2("B");
HashMap – Single Key and Multiple Values Using List
Map<String, List<String>> map = new HashMap<String, List<String>>();
// create list one and store values
List<String> One = new ArrayList<String>();
One.add("Apple");
One.add("Aeroplane");
// create list two and store values
List<String> Two = new ArrayList<String>();
Two.add("Bat");
Two.add("Banana");
// put values into map
map.put("A", One);
map.put("B", Two);
map.put("C", Three);
You can do something like this (add access modifiers as required):
Map<String,Map<String,String>> complexMap=new HashMap<String,Map<String,String>>();
You can insert data like this:
Map<String,String> componentMap = new HashMap<String,String>();
componentMap.put("foo","bar");
componentMap.put("secondFoo","secondBar");
complexMap.put("superFoo",componentMap);
The Generated Data Structure would be:
{superFoo={secondFoo=secondBar, foo=bar}}
This way each value for the key should have a unique identifier. Also gives O(1) for fetches,if keys are known.
Write a new class that holds all the values that you need and use the new class's object as the value in your HashMap
HashMap<String, MyObject>
class MyObject {
public String value1;
public int value2;
public List<String> value3;
}
Here is the code how to get extract the hashmap into arrays, hashmap that contains arraylist
Map<String, List<String>> country_hashmap = new HashMap<String, List<String>>();
//Creating two lists and inserting some data in it
List<String> list_1 = new ArrayList<String>();
list_1.add("16873538.webp");
list_1.add("16873539.webp");
List<String> list_2 = new ArrayList<String>();
list_2.add("16873540.webp");
list_2.add("16873541.webp");
//Inserting both the lists and key to the Map
country_hashmap.put("Malaysia", list_1);
country_hashmap.put("Japanese", list_2);
for(Map.Entry<String, List<String>> hashmap_data : country_hashmap.entrySet()){
String key = hashmap_data.getKey(); // contains the keys
List<String> val = hashmap_data.getValue(); // contains arraylists
// print all the key and values in the hashmap
System.out.println(key + ": " +val);
// using interator to get the specific values arraylists
Iterator<String> itr = val.iterator();
int i = 0;
String[] data = new String[val.size()];
while (itr.hasNext()){
String array = itr.next();
data[i] = array;
System.out.println(data[i]); // GET THE VALUE
i++;
}
}
How I can get the third value for the first key in this map? Is this possible?
Libraries exist to do this, but the simplest plain Java way is to create a Map of List like this:
Map<Object,ArrayList<Object>> multiMap = new HashMap<>();
It sounds like you're looking for a multimap. Guava has various Multimap implementations, usually created via the Multimaps class.
I would suggest that using that implementation is likely to be simpler than rolling your own, working out what the API should look like, carefully checking for an existing list when adding a value etc. If your situation has a particular aversion to third party libraries it may be worth doing that, but otherwise Guava is a fabulous library which will probably help you with other code too :)
For example:
Map<Object,Pair<Integer,String>> multiMap = new HashMap<Object,Pair<Integer,String>>();
where the Pair is a parametric class
public class Pair<A, B> {
A first = null;
B second = null;
Pair(A first, B second) {
this.first = first;
this.second = second;
}
public A getFirst() {
return first;
}
public void setFirst(A first) {
this.first = first;
}
public B getSecond() {
return second;
}
public void setSecond(B second) {
this.second = second;
}
}
This is what i found in a similar question's answer
Map<String, List<String>> hm = new HashMap<String, List<String>>();
List<String> values = new ArrayList<String>();
values.add("Value 1");
values.add("Value 2");
hm.put("Key1", values);
// to get the arraylist
System.out.println(hm.get("key1"));
RESULT: [Value 1, Value 2]
A standard Java HashMap cannot store multiple values per key, any new entry you add will overwrite the previous one.
Have you got something like this?
HashMap<String, ArrayList<String>>
If so, you can iterate through your ArrayList and get the item you like with arrayList.get(i).
I found the blog on random search, i think this will help for doing this: http://tomjefferys.blogspot.com.tr/2011/09/multimaps-google-guava.html
public class MutliMapTest {
public static void main(String... args) {
Multimap<String, String> myMultimap = ArrayListMultimap.create();
// Adding some key/value
myMultimap.put("Fruits", "Bannana");
myMultimap.put("Fruits", "Apple");
myMultimap.put("Fruits", "Pear");
myMultimap.put("Vegetables", "Carrot");
// Getting the size
int size = myMultimap.size();
System.out.println(size); // 4
// Getting values
Collection<String> fruits = myMultimap.get("Fruits");
System.out.println(fruits); // [Bannana, Apple, Pear]
Collection<string> vegetables = myMultimap.get("Vegetables");
System.out.println(vegetables); // [Carrot]
// Iterating over entire Mutlimap
for(String value : myMultimap.values()) {
System.out.println(value);
}
// Removing a single value
myMultimap.remove("Fruits","Pear");
System.out.println(myMultimap.get("Fruits")); // [Bannana, Pear]
// Remove all values for a key
myMultimap.removeAll("Fruits");
System.out.println(myMultimap.get("Fruits")); // [] (Empty Collection!)
}
}
Try using collections to store the values of a key:
Map<Key, Collection<Value>>
you have to maintain the value list yourself
Apache Commons collection classes is the solution.
MultiMap multiMapDemo = new MultiValueMap();
multiMapDemo .put("fruit", "Mango");
multiMapDemo .put("fruit", "Orange");
multiMapDemo.put("fruit", "Blueberry");
System.out.println(multiMap.get("fruit"));
// Mango Orange Blueberry
Maven Dependency
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 --
>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
Apart from all the answers here, I have a solution that I used and found it most useful if you know the length of multiple values to be added to your key.
In my case, it was 2, so I opted for this over a List<string>.
HashMap<String, String[]> multimap= new HashMap<>();
multimap.put("my_key", new String[]{"my_value1", "my_value2"});
Thinking about a Map with 2 keys immediately compelled me to use a user-defined key, and that would probably be a Class. Following is the key Class:
public class MapKey {
private Object key1;
private Object key2;
public Object getKey1() {
return key1;
}
public void setKey1(Object key1) {
this.key1 = key1;
}
public Object getKey2() {
return key2;
}
public void setKey2(Object key2) {
this.key2 = key2;
}
}
// Create first map entry with key <A,B>.
MapKey mapKey1 = new MapKey();
mapKey1.setKey1("A");
mapKey1.setKey2("B");
HashMap – Single Key and Multiple Values Using List
Map<String, List<String>> map = new HashMap<String, List<String>>();
// create list one and store values
List<String> One = new ArrayList<String>();
One.add("Apple");
One.add("Aeroplane");
// create list two and store values
List<String> Two = new ArrayList<String>();
Two.add("Bat");
Two.add("Banana");
// put values into map
map.put("A", One);
map.put("B", Two);
map.put("C", Three);
You can do something like this (add access modifiers as required):
Map<String,Map<String,String>> complexMap=new HashMap<String,Map<String,String>>();
You can insert data like this:
Map<String,String> componentMap = new HashMap<String,String>();
componentMap.put("foo","bar");
componentMap.put("secondFoo","secondBar");
complexMap.put("superFoo",componentMap);
The Generated Data Structure would be:
{superFoo={secondFoo=secondBar, foo=bar}}
This way each value for the key should have a unique identifier. Also gives O(1) for fetches,if keys are known.
Write a new class that holds all the values that you need and use the new class's object as the value in your HashMap
HashMap<String, MyObject>
class MyObject {
public String value1;
public int value2;
public List<String> value3;
}
Here is the code how to get extract the hashmap into arrays, hashmap that contains arraylist
Map<String, List<String>> country_hashmap = new HashMap<String, List<String>>();
//Creating two lists and inserting some data in it
List<String> list_1 = new ArrayList<String>();
list_1.add("16873538.webp");
list_1.add("16873539.webp");
List<String> list_2 = new ArrayList<String>();
list_2.add("16873540.webp");
list_2.add("16873541.webp");
//Inserting both the lists and key to the Map
country_hashmap.put("Malaysia", list_1);
country_hashmap.put("Japanese", list_2);
for(Map.Entry<String, List<String>> hashmap_data : country_hashmap.entrySet()){
String key = hashmap_data.getKey(); // contains the keys
List<String> val = hashmap_data.getValue(); // contains arraylists
// print all the key and values in the hashmap
System.out.println(key + ": " +val);
// using interator to get the specific values arraylists
Iterator<String> itr = val.iterator();
int i = 0;
String[] data = new String[val.size()];
while (itr.hasNext()){
String array = itr.next();
data[i] = array;
System.out.println(data[i]); // GET THE VALUE
i++;
}
}
How I can get the third value for the first key in this map? Is this possible?
Libraries exist to do this, but the simplest plain Java way is to create a Map of List like this:
Map<Object,ArrayList<Object>> multiMap = new HashMap<>();
It sounds like you're looking for a multimap. Guava has various Multimap implementations, usually created via the Multimaps class.
I would suggest that using that implementation is likely to be simpler than rolling your own, working out what the API should look like, carefully checking for an existing list when adding a value etc. If your situation has a particular aversion to third party libraries it may be worth doing that, but otherwise Guava is a fabulous library which will probably help you with other code too :)
For example:
Map<Object,Pair<Integer,String>> multiMap = new HashMap<Object,Pair<Integer,String>>();
where the Pair is a parametric class
public class Pair<A, B> {
A first = null;
B second = null;
Pair(A first, B second) {
this.first = first;
this.second = second;
}
public A getFirst() {
return first;
}
public void setFirst(A first) {
this.first = first;
}
public B getSecond() {
return second;
}
public void setSecond(B second) {
this.second = second;
}
}
This is what i found in a similar question's answer
Map<String, List<String>> hm = new HashMap<String, List<String>>();
List<String> values = new ArrayList<String>();
values.add("Value 1");
values.add("Value 2");
hm.put("Key1", values);
// to get the arraylist
System.out.println(hm.get("key1"));
RESULT: [Value 1, Value 2]
A standard Java HashMap cannot store multiple values per key, any new entry you add will overwrite the previous one.
Have you got something like this?
HashMap<String, ArrayList<String>>
If so, you can iterate through your ArrayList and get the item you like with arrayList.get(i).
I found the blog on random search, i think this will help for doing this: http://tomjefferys.blogspot.com.tr/2011/09/multimaps-google-guava.html
public class MutliMapTest {
public static void main(String... args) {
Multimap<String, String> myMultimap = ArrayListMultimap.create();
// Adding some key/value
myMultimap.put("Fruits", "Bannana");
myMultimap.put("Fruits", "Apple");
myMultimap.put("Fruits", "Pear");
myMultimap.put("Vegetables", "Carrot");
// Getting the size
int size = myMultimap.size();
System.out.println(size); // 4
// Getting values
Collection<String> fruits = myMultimap.get("Fruits");
System.out.println(fruits); // [Bannana, Apple, Pear]
Collection<string> vegetables = myMultimap.get("Vegetables");
System.out.println(vegetables); // [Carrot]
// Iterating over entire Mutlimap
for(String value : myMultimap.values()) {
System.out.println(value);
}
// Removing a single value
myMultimap.remove("Fruits","Pear");
System.out.println(myMultimap.get("Fruits")); // [Bannana, Pear]
// Remove all values for a key
myMultimap.removeAll("Fruits");
System.out.println(myMultimap.get("Fruits")); // [] (Empty Collection!)
}
}
Try using collections to store the values of a key:
Map<Key, Collection<Value>>
you have to maintain the value list yourself
Apache Commons collection classes is the solution.
MultiMap multiMapDemo = new MultiValueMap();
multiMapDemo .put("fruit", "Mango");
multiMapDemo .put("fruit", "Orange");
multiMapDemo.put("fruit", "Blueberry");
System.out.println(multiMap.get("fruit"));
// Mango Orange Blueberry
Maven Dependency
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 --
>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
Apart from all the answers here, I have a solution that I used and found it most useful if you know the length of multiple values to be added to your key.
In my case, it was 2, so I opted for this over a List<string>.
HashMap<String, String[]> multimap= new HashMap<>();
multimap.put("my_key", new String[]{"my_value1", "my_value2"});
Thinking about a Map with 2 keys immediately compelled me to use a user-defined key, and that would probably be a Class. Following is the key Class:
public class MapKey {
private Object key1;
private Object key2;
public Object getKey1() {
return key1;
}
public void setKey1(Object key1) {
this.key1 = key1;
}
public Object getKey2() {
return key2;
}
public void setKey2(Object key2) {
this.key2 = key2;
}
}
// Create first map entry with key <A,B>.
MapKey mapKey1 = new MapKey();
mapKey1.setKey1("A");
mapKey1.setKey2("B");
HashMap – Single Key and Multiple Values Using List
Map<String, List<String>> map = new HashMap<String, List<String>>();
// create list one and store values
List<String> One = new ArrayList<String>();
One.add("Apple");
One.add("Aeroplane");
// create list two and store values
List<String> Two = new ArrayList<String>();
Two.add("Bat");
Two.add("Banana");
// put values into map
map.put("A", One);
map.put("B", Two);
map.put("C", Three);
You can do something like this (add access modifiers as required):
Map<String,Map<String,String>> complexMap=new HashMap<String,Map<String,String>>();
You can insert data like this:
Map<String,String> componentMap = new HashMap<String,String>();
componentMap.put("foo","bar");
componentMap.put("secondFoo","secondBar");
complexMap.put("superFoo",componentMap);
The Generated Data Structure would be:
{superFoo={secondFoo=secondBar, foo=bar}}
This way each value for the key should have a unique identifier. Also gives O(1) for fetches,if keys are known.
Write a new class that holds all the values that you need and use the new class's object as the value in your HashMap
HashMap<String, MyObject>
class MyObject {
public String value1;
public int value2;
public List<String> value3;
}
Here is the code how to get extract the hashmap into arrays, hashmap that contains arraylist
Map<String, List<String>> country_hashmap = new HashMap<String, List<String>>();
//Creating two lists and inserting some data in it
List<String> list_1 = new ArrayList<String>();
list_1.add("16873538.webp");
list_1.add("16873539.webp");
List<String> list_2 = new ArrayList<String>();
list_2.add("16873540.webp");
list_2.add("16873541.webp");
//Inserting both the lists and key to the Map
country_hashmap.put("Malaysia", list_1);
country_hashmap.put("Japanese", list_2);
for(Map.Entry<String, List<String>> hashmap_data : country_hashmap.entrySet()){
String key = hashmap_data.getKey(); // contains the keys
List<String> val = hashmap_data.getValue(); // contains arraylists
// print all the key and values in the hashmap
System.out.println(key + ": " +val);
// using interator to get the specific values arraylists
Iterator<String> itr = val.iterator();
int i = 0;
String[] data = new String[val.size()];
while (itr.hasNext()){
String array = itr.next();
data[i] = array;
System.out.println(data[i]); // GET THE VALUE
i++;
}
}
How can I create and fetch associative arrays in Java like I can in PHP?
For example:
$arr[0]['name'] = 'demo';
$arr[0]['fname'] = 'fdemo';
$arr[1]['name'] = 'test';
$arr[1]['fname'] = 'fname';
Java doesn't support associative arrays, however this could easily be achieved using a Map. E.g.,
Map<String, String> map = new HashMap<String, String>();
map.put("name", "demo");
map.put("fname", "fdemo");
// etc
map.get("name"); // returns "demo"
Even more accurate to your example (since you can replace String with any object that meet your needs) would be to declare:
List<Map<String, String>> data = new ArrayList<>();
data.add(0, map);
data.get(0).get("name");
See the official documentation for more information
Java doesn't have associative arrays like PHP does.
There are various solutions for what you are doing, such as using a Map, but it depends on how you want to look up the information. You can easily write a class that holds all your information and store instances of them in an ArrayList.
public class Foo{
public String name, fname;
public Foo(String name, String fname){
this.name = name;
this.fname = fname;
}
}
And then...
List<Foo> foos = new ArrayList<Foo>();
foos.add(new Foo("demo","fdemo"));
foos.add(new Foo("test","fname"));
So you can access them like...
foos.get(0).name;
=> "demo"
You can accomplish this via Maps. Something like
Map<String, String>[] arr = new HashMap<String, String>[2]();
arr[0].put("name", "demo");
But as you start using Java I am sure you will find that if you create a class/model that represents your data will be your best options. I would do
class Person{
String name;
String fname;
}
List<Person> people = new ArrayList<Person>();
Person p = new Person();
p.name = "demo";
p.fname = "fdemo";
people.add(p);
Look at the Map interface, and at the concrete class HashMap.
To create a Map:
Map<String, String> assoc = new HashMap<String, String>();
To add a key-value pair:
assoc.put("name", "demo");
To retrieve the value associated with a key:
assoc.get("name")
And sure, you may create an array of Maps, as it seems to be what you want:
Map<String, String>[] assoc = ...
There is no such thing as associative array in Java. Its closest relative is a Map, which is strongly typed, however has less elegant syntax/API.
This is the closest you can get based on your example:
Map<Integer, Map<String, String>> arr =
org.apache.commons.collections.map.LazyMap.decorate(
new HashMap(), new InstantiateFactory(HashMap.class));
//$arr[0]['name'] = 'demo';
arr.get(0).put("name", "demo");
System.out.println(arr.get(0).get("name"));
System.out.println(arr.get(1).get("name")); //yields null
Well i also was in search of Associative array and found the List of maps as the best solution.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class testHashes {
public static void main(String args[]){
Map<String,String> myMap1 = new HashMap<String, String>();
List<Map<String , String>> myMap = new ArrayList<Map<String,String>>();
myMap1.put("URL", "Val0");
myMap1.put("CRC", "Vla1");
myMap1.put("SIZE", "Vla2");
myMap1.put("PROGRESS", "Vla2");
myMap.add(0,myMap1);
myMap.add(1,myMap1);
for (Map<String, String> map : myMap) {
System.out.println(map.get("URL"));
}
//System.out.println(myMap);
}
}
Java equivalent of Perl's hash
HashMap<Integer, HashMap<String, String>> hash;
Java doesn't have associative arrays, the closest thing you can get is the Map interface
Here's a sample from that page.
import java.util.*;
public class Freq {
public static void main(String[] args) {
Map<String, Integer> m = new HashMap<String, Integer>();
// Initialize frequency table from command line
for (String a : args) {
Integer freq = m.get(a);
m.put(a, (freq == null) ? 1 : freq + 1);
}
System.out.println(m.size() + " distinct words:");
System.out.println(m);
}
}
If run with:
java Freq if it is to be it is up to me to delegate
You'll get:
8 distinct words:
{to=3, delegate=1, be=1, it=2, up=1, if=1, me=1, is=2}
Use ArrayList < Map < String, String > >
Here a code sample :
ArrayList<Map<String, String>> products = new ArrayList<Map<String, String>>();
while (iterator.hasNext()) {
Map<String, String> product = new HashMap<String, String>();
Element currentProduct = iterator.next();
product.put("id",currentProduct.get("id"));
product.put("name" , currentProduct.get("name") );
products.add(product );
}
System.out.println("products : " + products);
Output :
products : [{id=0001, name=prod1}, {id=0002, name=prod2}]
Associative arrays in Java like in PHP :
SlotMap hmap = new SlotHashMap();
String key = "k01";
String value = "123456";
// Add key value
hmap.put( key, value );
// check if key exists key value
if ( hmap.containsKey(key)) {
//.....
}
// loop over hmap
Set mapkeys = hmap.keySet();
for ( Iterator iterator = mapkeys.iterator(); iterator.hasNext();) {
String key = (String) iterator.next();
String value = hmap.get(key);
}
More info, see Class SoftHashMap : https://shiro.apache.org/static/1.2.2/apidocs/org/apache/shiro/util/SoftHashMap.html
Object[][] data = {
{"mykey1", "myval1"},
{"mykey2", "myval2"},
{new Date(), new Integer(1)},
};
Yes, this require iteration for searchting value by key, but if you need all of them, this will be the best choice.
In JDK 1.5 (http://tinyurl.com/3m2lxju) there is even a note: "NOTE: This class is obsolete. New implementations should implement the Map interface, rather than extending this class."
Regards, N.
Actually Java does support associative arrays they are called dictionaries!
Thinking more about it, I would like to throw out tuples as a more general-purpose way of dealing with this problem. While tuples are not native to Java, I use Javatuples to provide me the same functionality which would exist in other languages. An example of how to deal with the question asked is
Map<Pair<Integer, String>, String> arr = new HashMap<Pair<Integer, String>, String>();
Pair p1 = new Pair(0, "name");
arr.put(p1, "demo");
I like this approach because it can be extended to triples and other higher ordered groupings with api provided classes and methods.
Regarding the PHP comment 'No, PHP wouldn't like it'. Actually, PHP would keep on chugging unless you set some very restrictive (for PHP) exception/error levels, (and maybe not even then).
What WILL happen by default is that an access to a non existing variable/out of bounds array element 'unsets' your value that you're assigning to. NO, that is NOT null. PHP has a Perl/C lineage, from what I understand. So there are: unset and non existing variables, values which ARE set but are NULL, Boolean False values, then everything else that standard langauges have. You have to test for those separately, OR choose the RIGHT evaluation built in function/syntax.
Is it possible to implement a HashMap with one key and two values?
Just as HashMap<userId, clientID,timeStamp>?
If not, is there any other way to implement the storage of multiple values e.g. one key and two values?
You could:
Use a map that has a list as the value. Map<KeyType, List<ValueType>>.
Create a new wrapper class and place instances of this wrapper in the map. Map<KeyType, WrapperType>.
Use a tuple like class (saves creating lots of wrappers). Map<KeyType, Tuple<Value1Type, Value2Type>>.
Use mulitple maps side-by-side.
Examples
1. Map with list as the value
// create our map
Map<String, List<Person>> peopleByForename = new HashMap<>();
// populate it
List<Person> people = new ArrayList<>();
people.add(new Person("Bob Smith"));
people.add(new Person("Bob Jones"));
peopleByForename.put("Bob", people);
// read from it
List<Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs[0];
Person bob2 = bobs[1];
The disadvantage with this approach is that the list is not bound to exactly two values.
2. Using wrapper class
// define our wrapper
class Wrapper {
public Wrapper(Person person1, Person person2) {
this.person1 = person1;
this.person2 = person2;
}
public Person getPerson1() { return this.person1; }
public Person getPerson2() { return this.person2; }
private Person person1;
private Person person2;
}
// create our map
Map<String, Wrapper> peopleByForename = new HashMap<>();
// populate it
peopleByForename.put("Bob", new Wrapper(new Person("Bob Smith"),
new Person("Bob Jones"));
// read from it
Wrapper bobs = peopleByForename.get("Bob");
Person bob1 = bobs.getPerson1();
Person bob2 = bobs.getPerson2();
The disadvantage to this approach is that you have to write a lot of boiler-plate code for all of these very simple container classes.
3. Using a tuple
// you'll have to write or download a Tuple class in Java, (.NET ships with one)
// create our map
Map<String, Tuple2<Person, Person> peopleByForename = new HashMap<>();
// populate it
peopleByForename.put("Bob", new Tuple2(new Person("Bob Smith",
new Person("Bob Jones"));
// read from it
Tuple<Person, Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs.Item1;
Person bob2 = bobs.Item2;
This is the best solution in my opinion.
4. Multiple maps
// create our maps
Map<String, Person> firstPersonByForename = new HashMap<>();
Map<String, Person> secondPersonByForename = new HashMap<>();
// populate them
firstPersonByForename.put("Bob", new Person("Bob Smith"));
secondPersonByForename.put("Bob", new Person("Bob Jones"));
// read from them
Person bob1 = firstPersonByForename["Bob"];
Person bob2 = secondPersonByForename["Bob"];
The disadvantage of this solution is that it's not obvious that the two maps are related, a programmatic error could see the two maps get out of sync.
No, not just as a HashMap. You'd basically need a HashMap from a key to a collection of values.
If you're happy to use external libraries, Guava has exactly this concept in Multimap with implementations such as ArrayListMultimap, HashMultimap, LinkedHashMultimap etc.
Multimap<String, Integer> nameToNumbers = HashMultimap.create();
System.out.println(nameToNumbers.put("Ann", 5)); // true
System.out.println(nameToNumbers.put("Ann", 5)); // false
nameToNumbers.put("Ann", 6);
nameToNumbers.put("Sam", 7);
System.out.println(nameToNumbers.size()); // 3
System.out.println(nameToNumbers.keySet().size()); // 2
Another nice choice is to use MultiValuedMap from Apache Commons. Take a look at the All Known Implementing Classes at the top of the page for specialized implementations.
Example:
HashMap<K, ArrayList<String>> map = new HashMap<K, ArrayList<String>>()
could be replaced with
MultiValuedMap<K, String> map = new MultiValuedHashMap<K, String>();
So,
map.put(key, "A");
map.put(key, "B");
map.put(key, "C");
Collection<String> coll = map.get(key);
would result in collection coll containing "A", "B", and "C".
Take a look at Multimap from the guava-libraries and its implementation - HashMultimap
A collection similar to a Map, but which may associate multiple values with a single key. If you call put(K, V) twice, with the same key but different values, the multimap contains mappings from the key to both values.
I use Map<KeyType, Object[]> for associating multiple values with a key in a Map. This way, I can store multiple values of different types associated with a key. You have to take care by maintaining proper order of inserting and retrieving from Object[].
Example:
Consider, we want to store Student information. Key is id, while we would like to store name, address and email associated to the student.
//To make entry into Map
Map<Integer, String[]> studenMap = new HashMap<Integer, String[]>();
String[] studentInformationArray = new String[]{"name", "address", "email"};
int studenId = 1;
studenMap.put(studenId, studentInformationArray);
//To retrieve values from Map
String name = studenMap.get(studenId)[1];
String address = studenMap.get(studenId)[2];
String email = studenMap.get(studenId)[3];
HashMap<Integer,ArrayList<String>> map = new HashMap<Integer,ArrayList<String>>();
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
list.add("xyz");
map.put(100,list);
If you use Spring Framework. There is: org.springframework.util.MultiValueMap.
To create unmodifiable multi value map:
Map<String,List<String>> map = ...
MultiValueMap<String, String> multiValueMap = CollectionUtils.toMultiValueMap(map);
Or use org.springframework.util.LinkedMultiValueMap
The easiest way would be to use a google collection library:
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
public class Test {
public static void main(final String[] args) {
// multimap can handle one key with a list of values
final Multimap<String, String> cars = ArrayListMultimap.create();
cars.put("Nissan", "Qashqai");
cars.put("Nissan", "Juke");
cars.put("Bmw", "M3");
cars.put("Bmw", "330E");
cars.put("Bmw", "X6");
cars.put("Bmw", "X5");
cars.get("Bmw").forEach(System.out::println);
// It will print the:
// M3
// 330E
// X6
// X5
}
}
maven link: https://mvnrepository.com/artifact/com.google.collections/google-collections/1.0-rc2
more on this: http://tomjefferys.blogspot.be/2011/09/multimaps-google-guava.html
Just for the record, the pure JDK8 solution would be to use Map::compute method:
map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);
Such as
public static void main(String[] args) {
Map<String, List<String>> map = new HashMap<>();
put(map, "first", "hello");
put(map, "first", "foo");
put(map, "bar", "foo");
put(map, "first", "hello");
map.forEach((s, strings) -> {
System.out.print(s + ": ");
System.out.println(strings.stream().collect(Collectors.joining(", ")));
});
}
private static <KEY, VALUE> void put(Map<KEY, List<VALUE>> map, KEY key, VALUE value) {
map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);
}
with output:
bar: foo
first: hello, foo, hello
Note that to ensure consistency in case multiple threads access this data structure, ConcurrentHashMap and CopyOnWriteArrayList for instance need to be used.
Yes and no. The solution is to build a Wrapper clas for your values that contains the 2 (3, or more) values that correspond to your key.
Yes, this is frequently called a multimap.
See: http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/collect/Multimap.html
Using Java Collectors
// Group employees by department
Map<Department, List<Employee>> byDept = employees.stream()
.collect(Collectors.groupingBy(Employee::getDepartment));
where Department is your key
String key= "services_servicename"
ArrayList<String> data;
for(int i = 0; i lessthen data.size(); i++) {
HashMap<String, String> servicesNameHashmap = new HashMap<String, String>();
servicesNameHashmap.put(key,data.get(i).getServiceName());
mServiceNameArray.add(i,servicesNameHashmap);
}
I have got the Best Results.
You just have to create new HashMap like
HashMap<String, String> servicesNameHashmap = new HashMap<String, String>();
in your for loop. It will have same effect like same key and multiple values.
import java.io.*;
import java.util.*;
import com.google.common.collect.*;
class finTech{
public static void main(String args[]){
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("1","11");
multimap.put("1","14");
multimap.put("1","12");
multimap.put("1","13");
multimap.put("11","111");
multimap.put("12","121");
System.out.println(multimap);
System.out.println(multimap.get("11"));
}
}
Output:
{"1"=["11","12","13","14"],"11"=["111"],"12"=["121"]}
["111"]
This is Google-Guava library for utility functionalities. This is the required solution.
I could not post a reply on Paul's comment so I am creating new comment for Vidhya here:
Wrapper will be a SuperClass for the two classes which we want to store as a value.
and inside wrapper class, we can put the associations as the instance variable objects for the two class objects.
e.g.
class MyWrapper {
Class1 class1obj = new Class1();
Class2 class2obj = new Class2();
...
}
and in HashMap we can put in this way,
Map<KeyObject, WrapperObject>
WrapperObj will have class variables: class1Obj, class2Obj
You can do it implicitly.
// Create the map. There is no restriction to the size that the array String can have
HashMap<Integer, String[]> map = new HashMap<Integer, String[]>();
//initialize a key chosing the array of String you want for your values
map.put(1, new String[] { "name1", "name2" });
//edit value of a key
map.get(1)[0] = "othername";
This is very simple and effective.
If you want values of diferent classes instead, you can do the following:
HashMap<Integer, Object[]> map = new HashMap<Integer, Object[]>();
Can be done using an identityHashMap, subjected to the condition that the keys comparison will be done by == operator and not equals().
I prefer the following to store any number of variables without having to create a separate class.
final public static Map<String, Map<String, Float>> myMap = new HashMap<String, Map<String, Float>>();
I am so used to just doing this with a Data Dictionary in Objective C. It was harder to get a similar result in Java for Android. I ended up creating a custom class, and then just doing a hashmap of my custom class.
public class Test1 {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addview);
//create the datastring
HashMap<Integer, myClass> hm = new HashMap<Integer, myClass>();
hm.put(1, new myClass("Car", "Small", 3000));
hm.put(2, new myClass("Truck", "Large", 4000));
hm.put(3, new myClass("Motorcycle", "Small", 1000));
//pull the datastring back for a specific item.
//also can edit the data using the set methods. this just shows getting it for display.
myClass test1 = hm.get(1);
String testitem = test1.getItem();
int testprice = test1.getPrice();
Log.i("Class Info Example",testitem+Integer.toString(testprice));
}
}
//custom class. You could make it public to use on several activities, or just include in the activity if using only here
class myClass{
private String item;
private String type;
private int price;
public myClass(String itm, String ty, int pr){
this.item = itm;
this.price = pr;
this.type = ty;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public String getType() {
return item;
}
public void setType(String type) {
this.type = type;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
We can create a class to have multiple keys or values and the object of this class can be used as a parameter in map.
You can refer to https://stackoverflow.com/a/44181931/8065321
Apache Commons collection classes can implement multiple values under same key.
MultiMap multiMapDemo = new MultiValueMap();
multiMapDemo .put("fruit", "Mango");
multiMapDemo .put("fruit", "Orange");
multiMapDemo.put("fruit", "Blueberry");
System.out.println(multiMapDemo.get("fruit"));
Maven Dependency
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>