简体   繁体   中英

How to remove items from a java list - by a set of positions?

Given a set of positions, Set<Integer> positionsToRemove , I'd like to remove all items from a list, List<?> list , that their position correspond to the values in the set.

public static void remove(List<?> list, Set<Integer> positionsToRemove) {
  // ?
}

Notes:

  • The list may be long.
  • The set may be long.
  • Be careful not to fall for IndexOutOfBounds or ConcurrentModificationException.
  • You can assume that the list and set do not hold nulls.

You must ensure to remove items in reverse , as otherwise the indices will become invalid.

You can do this very easily with a List :

public static void remove(List<?> list, Set<Integer> positionsToRemove) {
    final ListIterator<?> iter = list.listIterator(list.size());
    while (iter.hasPrevious()) {
        iter.previous();
        if (positionsToRemove.contains(iter.nextIndex())) {
            iter.remove();
        }
    }
}

This takes advantage of the ability if ListIterator to provide the current index and also it's ability to iterate in reverse.

It also does not rely on a "marker value" so null is allowed in the input List .

Obviously you could do this much more simply with an "old style" indexed loop:

public static void remove(List<?> list, Set<Integer> positionsToRemove) {
    for (int i = list.size() - 1; i >= 0; --i) {
        if (positionsToRemove.contains(i)) {
            list.remove(i);
        }
    }
}

But it should be noted that if the List lacks RandomAccess this will be O(n^2) , whereas the ListIterator based solution would be O(n) for a List that has O(1) remove .

It may be quicker to return a new List , depending on how may elements you are removing and also the type of the List - for an ArrayList the remove operation is quite expensive:

public static <T> List<T> remove(List<T> list, Set<Integer> positionsToRemove) {
    return IntStream.range(0, list.size())
            .filter(i -> !positionsToRemove.contains(i))
            .mapToObj(list::get)
            .collect(toList());
}
public static void remove(List<?> list, Set<Integer> positionsToRemove) {
    for (Integer position : positionsToRemove) {
        list.set((int)position, null);
    }
    for (Iterator<?> iterator = list.iterator(); iterator.hasNext(); ) {
        Object o =  iterator.next();
        if (o == null) iterator.remove();
    }
}
public static void remove(List<?> list, Set<Integer> positionsToRemove) {
    int i = 0;
    for (Iterator<?> iterator = list.iterator(); iterator.hasNext(); ++i) {
        iterator.next();
        if (positionsToRemove.contains(i)) iterator.remove();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM