AlikElzin-kilaka
AlikElzin-kilaka

Reputation: 36051

How to stream a map with collection using Java 8 streams?

I'd like to stream a map with collection using Java 8 streams.

For example, having the following data:

Map<String, Collection<Integer>> data;

I'd like to go over the elements handling each integer value with the corresponding key strings. For example:

data.keyValueStream((k,v)-> ...)

Any idea how to achieve this? Thanks.

* Regarding the question "Why do you need it?", it could be a bunch of reasons and I'm not sure it's important. Anyhow, I'll "flow" with you... My specific scenario is to batch insert into a DB all the values, under their specific key. Let's keep it a general Java 8 stream question...

Upvotes: 1

Views: 11935

Answers (4)

Eugene
Eugene

Reputation: 121048

While this may be a bit obvious, you can also write:

map.forEach((k, v) -> v.forEach(s -> System.out.println(k + "  " + s)))

Example, in Java 9.

Map< String , Collection< Integer > > map =
    Map.ofEntries(
        Map.entry( "alpha" , List.of( 1 , 2 , 3 ) ) ,
        Map.entry( "beta" , List.of( 4 , 5 , 6 ) ) ,
        Map.entry( "gamma" , List.of( 7 , 8 , 9 ) )
    )
;

map.forEach( ( k , v ) -> {
        v.forEach( s -> System.out.println( k + "  " + s ) );
    }
);

Upvotes: 2

Adam Siemion
Adam Siemion

Reputation: 16039

You can map your Map<String, Collection<Integer>> to List<Map.Entry<String, Integer>>:

data.entrySet().stream()
  .flatMap(e -> e.getValue().stream().map(v -> new HashMap.SimpleEntry<>(e.getKey(), v)))
  .forEach(e -> System.out.printf("key %s val %d%n", e.getKey(), e.getValue()));

or:

data.forEach((k, v) -> v.forEach(n -> System.out.printf("key %s val %d%n", k, n)));

Upvotes: 5

Pshemo
Pshemo

Reputation: 124275

I realize that you ware asking about stream version, but if you are NOT going to use parallelism simplest and probably more efficient option would be using nested loops. This way you can avoid spending time and space on creating temporary instances for each <Key,CollectionItem> pair.

Instead you can use

for (Map.Entry<String, Collection<Integer>> entry : map.entrySet()){
    String key = entry.getKey();
    for (Integer number : entry.getValye()){
        //here we have access to <key, number> pair, 
        //handle them as you wish;
    }
}

Upvotes: 3

Andreas
Andreas

Reputation: 159215

Streaming only processes a single value, so you can't get keyValueStream((k,v)-> ...), but you can get keyValueStream(x -> ...) where x is a tuple/pair.

Since you are starting with a Map, which can stream Entry objects (key/value pairs), and you want a key/value pair in your lambda, a stream of Entry objects seems appropriate.

Which means that you just want to flatten the nested collection, e.g. like this:

import java.util.AbstractMap.SimpleEntry;
data.entrySet()
    .stream()
    .flatMap(e -> e.getValue().stream().map(v -> new SimpleEntry<>(e.getKey(), v)))
    // At this point you have a Stream<Entry<String, Integer>> so you can e.g. do this:
    .forEach(e -> System.out.println(e.getKey() + "=" + e.getValue()))
;

Upvotes: 1

Related Questions