0% found this document useful (0 votes)
3 views

1KeyMultiValues

The document discusses various methods to implement a HashMap that can store multiple values under a single key, including using a list, a wrapper class, a tuple-like class, or multiple maps. It also mentions external libraries like Guava's Multimap and Apache Commons' MultiValuedMap as alternatives for handling this requirement more efficiently. Additionally, it provides a pure JDK8 solution using the Map::compute method for managing collections of values associated with keys.

Uploaded by

shardakec180
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

1KeyMultiValues

The document discusses various methods to implement a HashMap that can store multiple values under a single key, including using a list, a wrapper class, a tuple-like class, or multiple maps. It also mentions external libraries like Guava's Multimap and Apache Commons' MultiValuedMap as alternatives for handling this requirement more efficiently. Additionally, it provides a pure JDK8 solution using the Map::compute method for managing collections of values associated with keys.

Uploaded by

shardakec180
Copyright
© © All Rights Reserved
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 3

source :: https://stackoverflow.

com/questions/4956844/hashmap-with-multiple-values-
under-the-same-key
Is it possible for us to implement a HashMap with one key and two values. Just as
HashMap?

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.

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

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.

You might also like