248

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?

3

21 Answers 21

312

You could:

  1. Use a map that has a list as the value. Map<KeyType, List<ValueType>>.
  2. Create a new wrapper class and place instances of this wrapper in the map. Map<KeyType, WrapperType>.
  3. Use a tuple like class (saves creating lots of wrappers). Map<KeyType, Tuple<Value1Type, Value2Type>>.
  4. 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.

7
  • @vidhya: which in particular fits your problem? Are your mulitple objects the same type or different?
    – Paul Ruane
    Feb 10, 2011 at 14:49
  • @CoolMind I'm sure people can work their way around the mistakes: or you could correct them perhaps?
    – Paul Ruane
    Dec 24, 2015 at 16:16
  • @PaulRuane, sorry for a criticysm. Yeap, you are right, people can overcome them.
    – CoolMind
    Dec 24, 2015 at 23:52
  • @PaulRuane Where could I find this tuple class?
    – user5416120
    Feb 9, 2016 at 16:49
  • @DeliriousSyntax dzone.com/articles/whats-wrong-java-8-part-v It took me 10 seconds in a search engine.
    – Paul Ruane
    Feb 9, 2016 at 17:29
67

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
7
  • 2
    @Deepak: Search for guava multimap examples and you'll find sample code.
    – Jon Skeet
    Feb 10, 2011 at 18:11
  • 1
    @Deepak: Basically you'd build something like ArrayListMultimap yourself... or just use a HashMap<String, List<Integer>> or whatever. You'd need to create an empty list any time a value is added for the first time, basically.
    – Jon Skeet
    Feb 10, 2011 at 18:20
  • 1
    do you have a working example for HashMap<String, List<Integer>>
    – Deepak
    Feb 10, 2011 at 18:26
  • 9
    @Deepak: I suggest you try creating an example yourself, and if you get stuck, ask a question including the code as far as you've got. You'll learn a lot more that way.
    – Jon Skeet
    Feb 10, 2011 at 19:28
  • 1
    Multimap<String, String> multimap = ArrayListMultimap.create(); multimap.put("key", "value"); May 5, 2018 at 14:14
27

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".

0
15

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.

11

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];
1
  • 2
    To me this is the best answer. It's simpler, more concise, and less abstract.
    – Morey
    Jan 4, 2017 at 3:25
6
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);
0
6

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

0
5

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

0
4

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.

1
  • 1
    It is better to use computeIfAbsent. map.computeIfAbsent(key, k -> new ArrayList<>()).add(value);
    – user4910279
    Dec 30, 2016 at 0:54
2

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.

2

Yes, this is frequently called a multimap.

See: http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?com/google/common/collect/Multimap.html

0
1

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>>();
3
  • May I know how to input values to this map? In other words, how to write a simple mymap.put() statement for this?
    – Seshadri R
    Feb 19 at 11:33
  • 1
    HashMap<String, Float> exampleValue = new HashMap<String, Float>(); exampleValue.put("floatKey", 0.4); myMap.put("exampleKey", exampleValue);
    – ozgeneral
    Feb 19 at 18:18
  • Thank you very much for the immediate and concise response.
    – Seshadri R
    Feb 29 at 13:14
1

Using Java Collectors

// Group employees by department
Map<Department, List<Employee>> byDept = employees.stream()
                    .collect(Collectors.groupingBy(Employee::getDepartment));

where Department is your key

1
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.

1
 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.

2
  • It's a valid solution and I've used this approach on several occasions.
    – letowianka
    May 12, 2020 at 16:08
  • yes it working but it is showing data in [] formate i want those items one by one how to get that pls im stuck here May 13, 2020 at 7:10
0

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

0

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[]>();
0

Can be done using an identityHashMap, subjected to the condition that the keys comparison will be done by == operator and not equals().

0

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;
    }

}
0
0

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

0

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>
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.