Hashmap: One Key, Multiple Values

HashMap: One Key, multiple Values

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<>();

HashMap with multiple values under the same key

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.

how to add multiple values to single key in java

Since Map<K,V> maps one key to one value, you need V to be of type List<T>:

Map<String,List<Integer>> multiMap = new HashMap<>();

One consequence of having a type like that is that now the process of adding an item to a key consists of two steps: you must check if the list for the key exists, and then either add a new item to an existing list, or add a new list with a single item:

List<Integer> current = multiMap.get(key);
if (current == null) {
current = new ArrayList<Integer>();
multiMap.put(key, current);
}
current.add(val);

If you use Java 8, you can use computeIfAbsent to greatly simplify the code:

multiMap.computeIfAbsent(key, k -> new ArrayList<>()).add(value);

Java HashMap : How to add multiple values to one key?

Do not reuse the same reference of ArrayList. Create new ArrayList<Object[]>(); and add line to it. Do it as follows:

List result = dao.getServiceParam();
HashMap<Long,List<Object[]>> mapArray = new HashMap<Long, List<Object[]>>();
List<Object[]> listObj = null;
Object[] line = null, nextLine = null;
Long id = Long.valueOf(0), nextId = Long.valueOf(0);
if(!result.isEmpty()) {
for (int i=0; i< result.size(); i++) {
listObj = new ArrayList<Object[]>();
do{
line = (Object[])result.get(i);
if ((BigDecimal) line[0]!=null) {
listObj.add(line);
id = new Long(((BigDecimal) line[0]).longValue());
}
i++;
if(i<result.size()){
nextLine = (Object[])result.get(i);
if ((BigDecimal) nextLine[0]!=null) {
nextId = new Long(((BigDecimal) nextLine[0]).longValue());
}
}
}while(id.equals(nextId));
mapArray.put(id, listObj);
i--;
}
}

Feel free to comment in case of any doubt/issue.

Java HashMap, One key multiple Values, One map

To post my comment as an answer: use a Map<String, List<ToA>> like this:

Map<String, List<ToA>> wordkey = new HashMap<>();

ToA a = new ToA("Doolin", "Bill", "18580824-1464");
ToA b = new ToA("Dalton", "Bob", "18701005-2232");
ToA c = new ToA("James", "Jesse", "18470905-2401");
ToA d = new ToA("Dalton", "Emmet", "18710713-0818");

wordkey.put("Doolin", Arrays.asList(a));
wordkey.put("James", Arrays.asList(c));
wordkey.put("Dalton", Arrays.asList(b, d));

To print the names based on the input, you can do something like this:

System.out.println("Efternamn:");
name = scan.next();

List<ToA> toas = wordkey.get(name);
if (toas != null) {
System.out.println("ToAs");
for (ToA toa : toas) {
System.out.println("ToA: " + toa);
}
}
else {
System.out.println("No ToAs found for input: " + name);
}

Concurrent Map with one key and multiple values

tl;dr

personFavoriteColors.computeIfAbsent( 
"Alice" ,
( x -> new CopyOnWriteArrayList<>() )
)
.add( "Purple" )
;

personFavoriteColors.computeIfAbsent(
"Alice" ,
( x -> new CopyOnWriteArrayList<>() )
)
.add( "Gold" )
;

personFavoriteColors.toString(): [Purple, Gold]

Map::computeIfAbsent

Java now has multimap behavior built-in with new computeIfAbsent method defined on the Map interface.

Define your map.

ConcurrentMap< String , Set< String> > personFavoriteColors = new ConcurrentSkipListMap<>() ;

We are using a Map implementation that implements the ConcurrentMap interface for thread-safety as you requested. Java offers two such implementations.

Table of map implementations in Java 11, comparing their features

Use a single line to create a new list or set to hold the multiple values.

personFavoriteColors.computeIfAbsent( 
"Alice" ,
( x -> new CopyOnWriteArraySet<>() ) // Lambda expression. Run only if needed to run (if absent).
) // Returns the value of a map (a `Set` or `List` when desiring a multimap).
.add( "Purple" )
;

You may access the Set (or List) outside of the Map that owns it. So that Set (or List) must also be concurrent.

Here we used a concurrent set, CopyOnWriteArraySet as our value for the map.

For example:

Set< String > favoriteColorsForAlice = personFavoriteColors.get( "Alice" ) ;
System.out.println( favoriteColorsForAlice ) ;

See this code run live on IdeOne.com.

[Purple, Gold]



Related Topics



Leave a reply



Submit