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?
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.
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});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With