2

I have the following piece of code, that I want to translate using Java 8 stream API.

count = 0;
for (A a : someList) {
   if (a.get() == 1) {
     count++;
     newList.add(new X(count));
   }
}

How can I get that count when mapping?

newList = someList.stream
.filter(a -> a.get().equals("red"))
.map(a -> new X(count))
.collect(Collectors.toList());
Vinay Prajapati
  • 7,199
  • 9
  • 45
  • 86
CCC
  • 2,642
  • 7
  • 40
  • 62
  • Possible duplicate of [How to increment a value in Java Stream?](https://stackoverflow.com/questions/40304842/how-to-increment-a-value-in-java-stream) – mark42inbound Apr 26 '18 at 04:54

3 Answers3

5

The for loop version is better for this type of logic but if you really want to use Streams then I’d keep life simple and do it in two steps instead of trying to dump all the logic into a single stream pipeline which could lead to less readable code.

int count = (int)someList.stream()
                         .filter(a -> a.get().equals(“red”))
                         .count();

IntStream.rangeClosed(1, count)
         .mapToObj(X::new)
         .collect(toList());

As mentioned already this is by no means better than the for loop version but is here to illustrate, sometimes when using streams the best approach is to perform multiple passes instead of trying to fit everything into a single pipeline.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
  • I would not even call this “multiple passes”, as these two statements stream over entirely different things. It’s not even safe two assume that doing these two things in one loop will perform better than having two dedicated stream operations. That’s especially true when changing the second operation to `Arrays.asList(IntStream.rangeClosed(1, count).mapToObj(X::new).toArray(X[]::new))`, which has a known advantage over repeatedly adding to an `ArrayList`, as the stream operation doesn’t need capacity increase operations… – Holger Apr 26 '18 at 08:42
0

I think this might work;

AtomicInteger count = new AtomicInteger(0);
newList = someList.stream
.filter(a -> a.get().equals("red"))
.map(a -> new X(count.getAndIncrement()))
.collect(Collectors.toList());
CCC
  • 2,642
  • 7
  • 40
  • 62
  • 1
    it will work, but you have now introduced an `AtomicInteger` for absolutely no reason – Eugene Apr 25 '18 at 18:26
  • why? you can't have a simple integer because it should be immutable. – CCC Apr 25 '18 at 19:10
  • 1
    thats not the point, your non-stream solution with a plain loops is better. And you could use `int[]` of a single value for when you can guarantee a sequential run. Besides if you really want a stream solution the other answer has a better alternative – Eugene Apr 25 '18 at 19:13
  • 3
    and not immutable, but effectively final or final – Eugene Apr 25 '18 at 19:16
  • 3
    It *happens to do the intended thing under certain circumstances*. This is not the same as “it works”. – Holger Apr 26 '18 at 08:46
-1

Replace a -> new X(count) with a -> new X(++count). The ++ operator increments the variable, in this case count, and returns the old value if it's after the variable, or the new value if it's before the variable.

Anonymous
  • 491
  • 2
  • 12