4

I am trying to create a single map from list of maps. Which contains only key "1" and all the values of key "1" across different maps under that list using Java 8 stream API.

List<Map<String,Object>> list=new ArrayList<>();
Map<String,Object> map1=new HashMap<>();
map1.put("1", Arrays.asList(new String[] {"A"}));
map1.put("2", Arrays.asList(new String[] {"B"}));

Map<String,Object> map2=new HashMap<>();
map2.put("1", Arrays.asList(new String[] {"C"}));
map2.put("2", Arrays.asList(new String[] {"D"}));

Required output :- {1=[A, C]}

4
  • 1
    Why don't you declare list as List<Map<String,List<Object>>>? Otherwise why isn't {1=[[A], [C]]} the expected output? Commented Jan 24, 2020 at 7:38
  • 1
    @ernest_k I can Change the declaration to List<Map<String,List<Object>>> but I require output as {1=[A, C]}. {1=[A, C]} will be list of list right ? Commented Jan 24, 2020 at 7:52
  • @Chirag Right, that is exactly what is unclear with your question right now. Given the current code and List<Map<String,List<Strinig>>> as input type, the very first question you should ask yourself is why do you need such a complex representation of data, is there no way tto simplify it? Commented Jan 24, 2020 at 8:10
  • @Naman Need to return two lists from a process. So I am maintaining a map for it and that process can return multiple map, which makes it List of map. Any better suggestion Commented Jan 24, 2020 at 9:02

3 Answers 3

5

Because you have only one entry, then in this case, you need just to focus on the values, and for the key you can just use "1", for that you can create a Map like this :

Map<String, List<String>> result = new HashMap<>();
result.put("1", list.stream()
        .filter(e -> e.containsKey("1"))
        .flatMap(e -> e.values().stream())
        .flatMap(List::stream)
        .collect(Collectors.toList()));

Or as stated by Lino in the comment, you can also use :

Map<String, List<String>> result = list.stream()
    .filter(e -> e.containsKey("1"))
    .flatMap(e -> e.values().stream())
    .flatMap(List::stream)
    .collect(Collectors.groupingBy(t -> "1"));
Sign up to request clarification or add additional context in comments.

4 Comments

if you don't want to put into a map directly, you could use a groupingBy collector instead of toList: .collect(Collectors.groupingBy(i -> "1", i -> i))
@LinosaysReinstateMonica I don't get you sorry
Sorry I meant groupingBy(i -> "1") as can be seen here. Also i noticed that your code doesn't compile. Your stream collects into a List<List<String>> I think you missed a flatMap
Thank you @LinosaysReinstateMonica good idea, I put it in my answer :)
4

As mentioned by @ernest_k you should declare list as: List<Map<String, List<String>>>

You can use a groupingBy collector:

Map<String, List<String>> result = list.stream()
    .map(m -> m.get("1"))
    .filter(Objects::nonNull)
    .flatMap(Collection::stream)
    .collect(Collectors.groupingBy(t -> "1"));

You can get rid of the intermediate filter with this. But this may be more confusing (and effectively does the same):

Map<String, List<String>> result = list.stream()
    .map(m -> m.get("1"))
    .flatMap(l -> l == null ? Stream.empty() : l.stream())
    .collect(Collectors.groupingBy(t -> "1"));

2 Comments

Why don't you use this Map<String, List<String>> result = list.stream().filter(m -> m.containsKey("1")) .flatMap(m -> m.get("1").stream()).collect(Collectors.groupingBy(l -> "1"));
@RavindraRanwala that works as well, but does also effectively the same doesn't it? The map implementations I know almost always check if get(key) != null for containsKey
4

You can do:

Map<String, List<Object>> result = list.stream()
            .filter(entry -> entry.containsKey("1"))
            .map(entry -> (List<Object>) entry.get("1"))
            .collect(Collectors.toMap(t1 -> "1", 
                          ArrayList::new, (l1, l2) -> { l1.addAll(l2);return l1; }));

or use groupingBy collector :

Map<String, List<Object>> result2 = list.stream()
            .filter(entry -> entry.containsKey("1"))
            .flatMap(entry -> ((List<Object>) entry.get("1")).stream())
            .collect(Collectors.groupingBy(t->"1",Collectors.
                        collectingAndThen(Collectors.toList(),ArrayList::new)));

1 Comment

Why not use groupingBy?

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.