Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - cleanest way to iterate over a stream keeping track of index [duplicate]

Tags:

java

I'm trying to come up with a clean way to copy all elements of an ArrayList but one, based on its index.

In JavaScript we can filter by value, but also based on index as well. So what I'm trying to achieve will look something like that:

// nums is []
for(let i = 0; i <nums.length; i++) {
   let copyNums = nums.filter((n, index) => index !== i);
}

In Java best I could do so far is this, which is super long and verbose. Not to mention the I couldn't use i itself as it's not final otherwise I'm getting

Variable used in lambda expression should be final or effectively final

       // nums is ArrayList
       for (int i = 0; i < nums.size(); i++) {
            final int index = i;
            List<Integer> allElementsWithoutCurr = IntStream.range(0, nums.size())
                    .filter(j -> j != index)
                    .mapToObj(j -> nums.get(j))
                    .collect(Collectors.toList());
        }

Surely there is a better way to achieve this in Java?

like image 543
Anton Belev Avatar asked Dec 01 '25 03:12

Anton Belev


1 Answers

The simple way

List<Foo> result = new ArrayList<>(list);
result.remove(i);

For long lists and low values of i, this might be a bit slow because it has to shift the tail elements left, however for brevity and clarity you can't beat it.

The stream way

You can use a stream and keep track of the index by using AtomicInteger, whose reference is effectively final, but whose value may be changed:

AtomicInteger index = new AtomicInteger();
List<Foo> result = list.stream()
  .filter(x -> index.getAndIncrement() != i)
  .collect(toList());

For large lists this may be faster since no shift left is required, and you can do other stuff in the stream in the one operation.

Of course if you want to filter many elements based on their index, you can do that without any performance hit.

With a stream, you might not even need the list if you just want to do stuff with the result directly:

list.stream()
  .filter(x -> index.getAndIncrement() != i)
  .forEach(foo -> {doSomething with foo});
like image 81
Bohemian Avatar answered Dec 02 '25 17:12

Bohemian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!