Jatin
Jatin

Reputation: 35

Efficiently Merge two ArrayLists of Maps

Facing a challenge to come up with an efficient way of merging two ArrayLists of Maps.

The map looks like this:

{Username=User1, Role=Admin}

So one list looks like this:

List1 =  [{Username=User1, Role=Admin},{Username=User2, Role=Auditor}]

and so on.

There is another list:

List 2 = [{Username=User1, Role=Integrator},{Username=User2, Role=Manager}]

Note: The users have different roles in different lists.

What i want to end up with is:

MergedList = [{Username=User1, Role=[Admin,Integrator]},{Username=User2, Role=[Auditor,Manager}]

Another Note: The actual list has 50,000 maps and each map has 20entries!! Just tried to keep it simple here.

Below are the stuff i tried. But failed.

Tried putAll. Tried merge.

Tried something that I found in another post

map2.forEach((k, v) -> map3.merge(k, v, String::concat));

Upvotes: 2

Views: 424

Answers (2)

Samuel Philipp
Samuel Philipp

Reputation: 11042

You can use Java Streams to achieve this:

Map<String, List<String>> result = Stream.concat(users1.stream(), users2.stream())
        .collect(Collectors.groupingBy(m -> m.get("Username"), Collectors.mapping(m -> m.get("Role"), Collectors.toList())));

This groups all the users and collects their roles.

The result will be:

{User1=[Admin, Integrator], User2=[Auditor, Manager]}

Upvotes: 1

Nikolas
Nikolas

Reputation: 44398

With regard to the performance and massive amount of data, I recommend you to avoid any usage of (although it is quite quick itself) and the Map::merge method.

Here you have to stick with the constructs closes to the JVM level and for-loops are your friends, here is the simplest approach I am aware of that might work:

final Map<String, Set<String>> newMap = new HashMap<>();

for (Map<String, String> map: list) {                        // iterate the List<Map>
    for (Entry<String, String> entry: map.entrySet()) {      // iterate the entries
        final String key = entry.getKey();                   // get the entry's key
        newMap.computeIfAbsent(key, k -> new HashSet<>());   // compute a new pair
        newMap.get(key).add(entry.getValue());               // add a value in any case
    }
}

Set prevents duplicate values.

This solution assumes the following data structure. Slight variations are easy to apply to the solution above.

List<Map<String, String>> list = new ArrayList<>();

Map<String, String> map1 = new HashMap<>();
map1.put("User1", "Admin");
map1.put("User2", "Auditor");

Map<String, String> map2 = new HashMap<>();
map2.put("User1", "Integrator");
map2.put("User2", "Manager");
map2.put("User3", "Coffee machine");

list.add(map1);
list.add(map2);

Upvotes: 1

Related Questions