Display the first element of the flow in a different way than rest

Is there a way in the Java Stream API to display the first element of a stream differently than the other?

Equivalent to this code:

List<Bar> barList = new ArrayList<>();

for (int i=0; i<fooList.size(); i++) {
    Foo foo = fooList.get(i);
    Foo modifiedFoo = foo.getModifiedFoo();
    if (i == 0) {
        barList.add(new Bar(modifiedFoo, false));
    }else {
        barList.add(new Bar(modifiedFoo, true));
    }
}

Stream<Bar> = barList.stream();

Note. I already have a stream setup, and I want some operations after the first display

fooList.stream()
        .map(Foo::getModifiedFoo)
        .(May be Some operation here to get different new Bar for first modifiedFoo)
        .map(modifiedFoo -> new Bar(modifiedFoo, true));
+4
source share
4 answers

I would get the first element by creating Streamfrom it and applying the necessary mappings. Then I will take the rest of the list, create a stream from it and apply various mappings. Then concatflows. Something like that:

Stream<Bar> first = Stream.of(fooList.get(0))
    .map(Foo::getModifiedFoo)
    .map(modifiedFoo -> new Bar(modifiedFoo, false));

Stream<Bar> others = fooList.subList(1, fooList.size()).stream()
    .map(Foo::getModifiedFoo)
    .map(modifiedFoo -> new Bar(modifiedFoo, true));

Stream<Bar> bars = Stream.concat(first, others).flatMap(s -> s);

Another approach:

Stream<Bar> bars = IntStream.range(0, fooList.size())
    .mapToObj(i -> new Bar(fooList.get(i).getModifiedFoo(), i > 0));

This method is concise and does the job pretty well.

+7
source

IntStream, , mapToObj , ,

List<Bar> barList = IntStream.range(0, fooList.size())
                             .mapToObj(i -> (i == 0 ? new Bar (fooList.get(i), false) : 
                                                      new Bar(fooList.get(i),true)))
                             .collect(Collectors.toList());

, , IntStream, 1.

.

+1

I can offer two paths, but I find your path more direct.

C IntStream, for example:

List<Bar> barList = new ArrayList<>();
IntStream.range(0, fooList.size())
         .forEach(i->{
                if (i == 0) {
                    barList.add(new Bar(foo, false));
                }else {
                    barList.add(new Bar(foo, true));
                }
         }
);

This is not a real functional approach ( forEach()use and no Collector) because it supports the current List index.

Alternatively, you can use a more functional approach, but I do not find it more direct:

List<Bar> barList = IntStream.range(0, fooList.size())
                             .mapToObj(i->{
                                    Foo foo = fooList.get(i);
                                    if (i == 0) {
                                        return new Bar(foo, false);
                                    }
                                    return new Bar(foo, true));                                     
                             })
                             .collect(Collectors.toList());
+1
source

Although I think the accepted answer is better, here is an alternative approach.

    int[] counter = {-1};

    Stream<Bar> barListStream = fooList.stream().map(foo -> {
          counter[0]++;
          return new Bar(mfoo.getModifiedFoo(), counter[0]>0);
       }).collect(Collectors.toList()).stream();
0
source

Source: https://habr.com/ru/post/1695253/


All Articles