Mark
Mark

Reputation: 273

Removing multiple ranges of element from a List<Object>

My list of objects can have such elements eg1:

[vale11, value12, value13, null, null, null, value21, value22, value23, value31, value32, value33]

eg2:

[vale11, value12, value13, null, null, null, null, null, null, value31, value32, value33]

eg3:

[vale11, value12, value13, null, null, null, value21, value22, value23, null, null, null]

eg4:

[vale11, null, value13, null, null, null, value21, value22, value23, value31, value32, null]

I want to remove the null values but not all (note eg4) and only those in a range started from certain index. So in eg1 would be something like:

list.sublist(3, 6).clear();

eg2:

list.sublist(3, 6).clear();
list.sublist(6, 9).clear();//it's not going to work

I know the starting indexes and a number of next elements (always the same)

Sometimes it would be 1 range, sometimes 3 , 5 ... How to clear the original list with the use of a loop or streams ?

Upvotes: 3

Views: 304

Answers (3)

Holger
Holger

Reputation: 298429

If you want to remove null elements from a List, you can do it as simple as

list.removeIf(Objects::isNull);

Of course, you can restrict the operation to a certain range like

list.subList(start, end).removeIf(Objects::isNull);

If the actual task is to remove predefined ranges from a list (and the information that there might be null elements at these place is actually irrelevant), you can use this answer (process the ranges in descending order), if the ranges don’t overlap.

If the ranges might overlap, you can use

BitSet toRemove = new BitSet(list.size());
toRemove.set(firstRangeStart, firstRangeEnd);
toRemove.set(secondRangeStart, secondRangeEnd);
// etc
for(int e = toRemove.length(), s; e > 0; e = toRemove.previousSetBit(s)+1)
    list.subList((s=toRemove.previousClearBit(e-1))+1, e).clear();

This will fuse adjacent and overlapping ranges before processing the resulting ranges in descending order.

Upvotes: 0

Mạnh Quyết Nguyễn
Mạnh Quyết Nguyễn

Reputation: 18235

Use can do it with a loop:

Below method will remove the elements whose startIndex <= index <= endIndex

<T> List<T> chopList(List<T> originalList, int startIndex, int endIndex) {
    // Your code to check original list, validate startIndex, endIndex must inrange...
    return IntStream.range(0, originalList.size() - 1)
                    .filter(i -> i < startIndex || i > endIndex)
                    .mapToObj(originalList::get)
                    .collect(toList());
}

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726849

You can use your technique with a little twist: order your ranges on the initial index in descending order. The rationale here is that as long as you go from a higher index to a lower index, and the ranges do not "cross over", the indexing is going to remain consistent.

Hence, clearing out sublist(6, 9) followed by sublist(3, 6) is going to work without a problem:

//  0        1       2       3     4     5     6     7     8      9       10       11
[vale11, value12, value13, null, null, null, null, null, null, value31, value32, value33]
//                                           ^^^^^^^^^^^^^^^^ [6, 9)
//                         ^^^^^^^^^^^^^^^^ [3, 6)

Upvotes: 2

Related Questions