dejvid
dejvid

Reputation: 123

Java 8 join two lists of maps

Is there any way in Java8 using Streams API to join two lists of maps? Let's say I do have:

List #1

[  
   {  
      id=1, attr1='a', attr2='b'
   },
   {  
      id=2, attr1='c', attr2='d'
   },
   {  
      id=3, attr1='e', attr2='f'
   }
]

List #2

[  
       {  
          id=1, attr3='x', attr4='y'
       },
       {  
          id=2, attr3='x', attr4='z'
       },
       {  
          id=3, attr3='z', attr4='y'
       }
    ]

Now I would like to join these 2 lists by key ID (just list an SQL join), the output would be:

[  
       {  
          id=1, attr1='a', attr2='b', attr3='x', attr4='y'
       },
       {  
          id=2, attr1='c', attr2='d', attr3='x', attr4='z'
       },
       {  
          id=3, attr1='e', attr2='f', attr3='z', attr4='y'
       }
    ]

Thanks a lot!

Upvotes: 1

Views: 3400

Answers (3)

rostIvan
rostIvan

Reputation: 294

final List<HashMap<String, String>> joinedById = list1.stream()
            .flatMap(m1 -> list2.stream()
                    .filter(y -> m1.get("id").equals(y.get("id")))
                    .map(m2 -> new HashMap<String, String>() {{
                        putAll(m1);
                        putAll(m2);
                    }}))
            .collect(Collectors.toList());

Upvotes: 4

Ayhan APAYDIN
Ayhan APAYDIN

Reputation: 1648

Your data structure of using id key in map; kind of makes this a bit unusual but here is an example with stream collector. Since your map values are both int and String I used Map<String, Object>

import java.util.*;
public class JoinTwoListofMaps {
    public static void main(String... args){
        List<Map<String, Object>> list1 = new ArrayList<>();
        List<Map<String, Object>> list2 = new ArrayList<>();
        Map<String, Object> map1_1 = new HashMap<>();
            map1_1.put("id",1);
            map1_1.put("attr1","a");
            map1_1.put("attr2","b");
        list1.add(map1_1);
        Map<String, Object> map2_1 = new HashMap<>();
            map2_1.put("id",1);
            map2_1.put("attr3","x");
            map2_1.put("attr4","y");
        list2.add(map2_1);
        System.out.println(joinTwoListOfMaps(list1, list2));
    }
    @SafeVarargs
    public static List<Map<String, Object>> joinTwoListOfMaps(List<Map<String, Object>>... listsOfMaps){
        List<Map<String, Object>> finalList = Arrays.stream(listsOfMaps).collect(ArrayList::new, List::addAll, List::addAll);
        return finalList.stream().collect(ArrayList::new, (list, mapToMerge) ->{
            Optional<Map<String, Object>> mapWithSameID = list.stream()
                    .filter(map -> map.get("id").equals(mapToMerge.get("id"))).findFirst();
            if (mapWithSameID.isPresent()) mapWithSameID.get().putAll(mapToMerge);
            else list.add(mapToMerge);
        }, ArrayList::addAll);
    }
}

Upvotes: 1

Anonymous
Anonymous

Reputation: 86276

There are lots of ways, with and without streams. The best way would depend on the more exact input requirements, which you haven’t given us. The following would work for the example lists in your question:

    if (list1.size() != list2.size()) {
        throw new IllegalStateException("Lists don’t match, not same size");
    }

    List<Map<String, Character>> comnbinedList = IntStream.range(0, list1.size())
            .mapToObj(i -> {
                    Map<String, Character> m1 = list1.get(i);
                    Character id1 = m1.get("id");
                    Map<String, Character> m2 = list2.get(i);
                    Character id2 = m1.get("id");
                    if (! id1.equals(id2)) {
                        throw new IllegalStateException("Lists don’t match, id " + id1 + " != " + id2);
                    }
                    HashMap<String, Character> mergedMap = new HashMap<>(m1);
                    mergedMap.putAll(m2);
                    return mergedMap; 
                })
            .collect(Collectors.toList());

The result is:

[{id=1, attr2=b, attr1=a, attr4=y, attr3=x}, {id=2, attr2=d, attr1=c, attr4=z, attr3=x}, {id=3, attr2=f, attr1=e, attr4=y, attr3=z}]

You will want to declare "id" a constant, of course.

Upvotes: 1

Related Questions