0

The following example may be trivial, but I have created it to show what I need to achieve using different data (not integers). This code is runnable etc.

List<List<Integer>> master = new ArrayList<>();
for (int i = 0; i < 10; i++) {
    List<Integer> inner = new ArrayList<Integer>();
    master.add(inner);
    for (int j = 0; j < 10; j++) {
        inner.add(i * 10 + j);
    }
}
System.out.println(master);
//lets make single collections from that but add 1000 to every element - this represents some intermediate operations to generate part of final result
List<Integer> finalAccumulated = new ArrayList<Integer>(); // this will represent our accumulated, final result
for (List<Integer> topLvl : master) {
    ArrayList<Integer> intermedialeAccumulated = new ArrayList<>(); //this step is important as it represents returning a collection of results for stream#map not single result
    for (Integer nested : topLvl) { // this represents stream#map (or maybe collector?)
        intermedialeAccumulated.add(nested + 1000);
    }
    finalAccumulated.addAll(intermedialeAccumulated); // this represent accumulation of collection of results, not just single result like stream#map do
}
System.out.println(finalAccumulated);

How to get the same result as in finalAccumulated using single Stream. By single I mean that in call chain there can be only single terminate action so the resulting form would be

finalAccumulated=master.stream()...intermediateCalls()...terminateCollectingCall();

Online ide with running code here

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • 5
    `flatMap`: http://stackoverflow.com/questions/25147094/turn-a-list-of-lists-into-a-list-using-lambdas. Where are you stuck? – Tunaki Sep 02 '16 at 12:17
  • @Tunaki you are right, flatMap is the way to go. Simply speaking there is no other way then create some intermediate streams. I was curious if this can be avoided. Thank you again. – Antoniossss Sep 02 '16 at 12:45

3 Answers3

2

Just use a flat map:

List<Integer> finalAccumulated = master
  .stream()
  .flatMap((x) -> x.stream())
  .map((i) -> i + 1000)
  .collect(Collectors.toList());
Thomas Jungblut
  • 20,854
  • 6
  • 68
  • 91
  • 1
    The parenthesis around `x` and `i` aren't necessary. They actually add some overhead when reading. You can even write `.flatMap(List::stream)` to avoid using intermediate variables. – Olivier Grégoire Sep 02 '16 at 13:25
  • @OlivierGrégoire I'm pretty sure that the intermediate variable will get allocated anyway, even if you just pass the method reference around. In the end it is calling an interface method with this parameter, so you won't save the allocation. – Thomas Jungblut Sep 02 '16 at 14:58
  • Sorry, I should have said "declaring" instead of "using". That's what I actually meant. Because you don't declare it, it's already done. – Olivier Grégoire Sep 03 '16 at 07:32
  • If you won’t go that deep into detail, using the method reference `List::stream` does not only save a local variable, but an entire method stack frame. But for most use cases, it’s just an unimportant detail, as @Olivier Grégoire already pointed out, with a method reference, you save a *declaration*, i.e. don’t have to introduce a new identifier. – Holger Sep 05 '16 at 13:47
-1

Here's how to produce the same finalAccumulated using a single Stream

List<Integer> finalAccumulated = IntStream.range(1000, 1000 + 10 * 10).boxed().collect(Collectors.toList());

Here would be an over-engineered and generic approach for such an operation

private static <T> List<T> flattenWith(List<List<T>> master, Function<T, T> transform) {
        return master.stream()
                     .flatMap(List::stream)
                     .map(transform)
                     .collect(Collectors.toList());
    }

Usage

flattenWith(master, x -> x + 1000)
Spotted
  • 4,021
  • 17
  • 33
  • 1
    Doesn't start from `master`, althought it produces the same result, but for the example code only. – Tunaki Sep 02 '16 at 12:22
  • @Tunaki exactly. I need more generic code. – Antoniossss Sep 02 '16 at 12:23
  • @Tunaki I know, I just wanted to point out that the question was a bit vague and could lead to such answer (that matches what is asked but not the way one would expect it). – Spotted Sep 02 '16 at 12:24
  • 2
    The question is quite clear in that it is only an example. It's like answering "How to print the first 3 prime numbers" with `System.out.println("2, 3, 5")` and leaving everyone to wonder how to print the first 100. – Tunaki Sep 02 '16 at 12:27
  • @Antoniossss I've added a more generic example – Spotted Sep 02 '16 at 12:32
  • @Spotted iv ended up using `list.parallelStream().map(mappingFunction).flatMap(MappingFunctionReturnType::stream).collect(Collectors.toList)` and this is exaclty what i needed thus this uses multiple intermediate streams i guess but there is no oway to do it on single stream. Thanks for the effort. – Antoniossss Sep 02 '16 at 12:43
-1
 private static void test() {
        List<List<Integer>> master = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            List<Integer> inner = new ArrayList<Integer>();
            master.add(inner);
            for (int j = 0; j < 10; j++) {
                inner.add(i * 10 + j);
            }
        }
        System.out.println(master);
//lets make single collections from that but add 1000 to every element - this represents some intermediate operations to generate part of final result
        List<Integer> finalAccumulated = new ArrayList<Integer>(); // this will represent our accumulated, final result
        for (List<Integer> topLvl : master) {
            ArrayList<Integer> intermedialeAccumulated = new ArrayList<>(); //this step is important as it represents returning a collection of results for stream#map not single result
            for (Integer nested : topLvl) { // this represents stream#map (or maybe collector?)
                intermedialeAccumulated.add(nested + 1000);
            }
            finalAccumulated.addAll(intermedialeAccumulated); // this represent accumulation of collection of results, not just single result like stream#map do
        }
        //map then using flatmap
        List<Integer> finalAccumulated2 = master.stream().map(topLvl -> {
            ArrayList<Integer> intermedialeAccumulated = new ArrayList<>();
            for (Integer nested : topLvl) { 
                intermedialeAccumulated.add(nested + 1000);
            }
            return intermedialeAccumulated;
        }).flatMap(intermedialeAccumulated -> intermedialeAccumulated.stream())
                .collect(Collectors.toList());
    }
csenga
  • 3,819
  • 1
  • 21
  • 31