1

I have two lists of Map<String, Object> as shown below:

List1=[ {ID=1, actor="A", film="AA"}, 
        {ID=1, actor="B", film="AA"} ]

List2={ [ID = 1, director="C"] } 

Result = { [ID=1, actor="A", film="AA", director="C"], 
           [ID=1, actor="B", film="AA", director="C"] }

I want to use the Stream class in Java 8 to join these lists.

How do I join the to get the value of Result shown?

Is the Stream class in Java 8 fast and stable if List1 and List2 are very big?

6
  • Why not simply add all the entries? list1.addAll(list2); Commented Feb 4, 2017 at 2:48
  • Cannot use addAll method because the result is different with above. Commented Feb 4, 2017 at 3:02
  • @nguyenduta What's the key for the Maps in the first list. Is it the actor? How about the key for the Maps in the second list? Commented Feb 4, 2017 at 18:39
  • @Cking I want to join these lists on ID Commented Feb 5, 2017 at 7:58
  • Yes but what are the keys that you are inserting in the Maps? Commented Feb 5, 2017 at 7:59

2 Answers 2

1

Ah now I understand what you want :) I don't know if there is a better way with streams but here is a solution which would work.

List<Map<String, String>> resultList = l1.stream()
        .map(m1 -> {
           Map<String, String> map = new HashMap<>();
           map.putAll(m1);
           l2.stream()
               .filter(m2 -> map.get("ID").equals(m2.get("ID")))
               .findFirst()
               .ifPresent(m2 -> map.put("director", m2.get("director")));
           return map;
        })
        .collect(Collectors.toList());

The above code generates a new List resultList and does not modify the other lists List1 and List2. If it does not matter if List1 gets modified or not you could do it in a cleaner, more readable way.

l1.forEach(m1 -> l2.stream()
    .filter(m2 -> m1.get("ID").equals(m2.get("ID")))
    .findFirst()
    .ifPresent(m2 -> m1.putIfAbsent("director", m2.get("director"))));

This way the entries of list1 get modified. So with the above example list1 is becomes the joined list. But it's actually good practice to have methods without any side effects. So I would not prefer the above example.

I would recommend a method getJoinedList which returns a new List and does not modify the other lists. And in this case I would not use streams but the old-fashioned for-loop.

private static List<Map<String, String>> getJoinedList(
    List<Map<String, String>> l1, List<Map<String, String>> l2) {

    List<Map<String, String>> result = new ArrayList<>();
    for (Map<String, String> m1 : l1) {
        Map<String, String> newMap = new HashMap<>();
        newMap.putAll(m1);
        for (Map<String, String> m2 : l2) {
            if (m1.get("ID").equals(m2.get("ID"))) {
                newMap.put("director", m2.get("director"));
                break;
            }
        }
        result.add(newMap);
    }

    return result;
}

Then you just can call the method like this.

List<Map<String, String>> joinedList = getJoinedList(l1, l2);
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! I will try it. :)
1

If performance matters, you should first build an index of directors:

Map<Object, Object> directors = list2.stream()
    .collect(Collectors.toMap(m -> m.get("ID"), m -> m.get("director")));

Then you can merge the directors to the list entries easily:

list1.stream().forEach(m -> m.put("director", directors.get(m.get("ID"))));

Accesing the director via a Map will be faster than searching the director for each list entry.

10 Comments

The OP seems to have a List of Map objects.
@CKing Yes, that's what I do have as well.
What I am trying to figure out is what exactly does m.get(“ID") and m.get("director") do. The OP doesn't mention that hey is using the strings "ID" and "director" as keys in the maps.
@CKing Yes, he did. See the first line. Here's some code: pastebin.com/XiDDjQBZ
I saw your code and that's exactly my question. The OP provided sample input data for list1 as [ {ID=1, actor="A", film="AA"}, {ID=1, actor="B", film="AA"} ]. Pay special attention to the curly braces and the comma. The first map in the list is {ID=1, actor="A", film="AA"} followed by a ,. The second map in the list is {ID=1, actor="B", film="AA"}. But the structure you assume is {{"ID",1},{"actor","A"},{"film","AA"}} , {{"ID",1},{"actor","B"},{"film","AA"}}. That's why I asked the OP about the keys in a comment.
|

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.