从ArrayList中删除多个元素

42

我有一堆索引,想从 ArrayList 中删除这些索引对应的元素。我不能简单地连续使用 remove() 方法,因为每次删除后元素都会被移动。我该如何解决这个问题?

16个回答

49

要删除 indexes 处的元素:

Collections.sort(indexes, Collections.reverseOrder());
for (int i : indexes)
    strs.remove(i);

或者,使用Java 8中的Stream API:

indexes.sort(Comparator.reverseOrder());
indexes.stream().mapToInt(i -> i).forEach(l::remove);

Arrays.sort() 如果处理数组的话 ^^ - T_01

36

将索引按降序排序,然后逐个删除。这样做,就不会影响到你之后想要删除的任何索引。

如何进行排序取决于你用来存储索引的集合类型。如果是列表,你可以这样做:

List<Integer> indices;
Collections.sort(indices, new Comparator<Integer>() {
   public int compare(Integer a, Integer b) {
      //todo: handle null
      return b.compareTo(a);
   }
}

编辑

@aioobe找到了我没能找到的帮助程序。 相比上面的方法,您可以使用

Collections.sort(indices, Collections.reverseOrder());

4
无需重新发明反向反向比较器。请参见我的回答 - aioobe
@aioobe:谢谢,我以为在Collections API中有一种方法可以做到这一点,但我找不到它。 - Mark Peters
如果你有一个数组,可以使用Arrays.sort()函数进行排序。 - T_01
我不明白,按数组排序如何改变需要移位的事实?例如,如果数组是{ 8, 5, 9, 1, 4, 7 },用户想要移除154。如果你将数组逆向排序为{ 9, 8, 7, 5, 4, 1 },那也无法更接近实现目标。 - Hatefiend
@Hatefiend:我没有说要对进行排序,我是说要对索引进行排序。所以在你的例子中,索引将是1、3、4。排序后将是[4, 3, 1]。按照这个顺序删除它们意味着后续删除的索引仍然有效。删除4(在索引4处)后,5和1仍将分别位于索引1和3。依此类推。 - Mark Peters

20

我来这里是为了删除特定范围内的元素(即在两个索引之间的所有元素),然后找到了这个:

list.subList(indexStart, indexEnd).clear()

java.util.ArrayList类的subList()方法用于返回此列表中指定fromIndex(包括)和toIndex(不包括)之间部分的视图。(如果fromIndex和toIndex相等,则返回的列表为空。)返回的列表由此列表支持,因此在返回的列表中进行非结构性更改会反映在此列表中,反之亦然。返回的列表支持所有可选的列表操作。 - Theo Briscoe

5
你可以从最大索引开始向下删除元素,或者如果你有要删除的对象的引用,可以使用removeAll方法。

4
你可能希望使用 subList 方法来选择你想要删除的索引范围,然后调用 clear() 方法。
(请注意第二个参数是排除的,例如在这种情况下,我传递 2 表示只有索引 0 和 1 将被删除。)
public static void main(String[] args) {
    ArrayList<String> animals = new ArrayList<String>();
    animals.add("cow");
    animals.add("dog");
    animals.add("chicken");
    animals.add("cat");
    animals.subList(0, 2).clear();
    for(String s : animals)
        System.out.println(s);
}

结果将会是: 鸡 猫


谢谢!这是一个很好的List范围操作,用于从List中获取子列表。方法的文档-> https://docs.oracle.com/javase/7/docs/api/java/util/List.html#subList(int, int) - Isaac Philip

3

2
似乎无法使用removeRange方法,除非您扩展ArrayList,因为该方法是protected - Sanghyun Lee
@SanghyunLee 为什么要用 protected 呢? - android developer

2
我认为"Nanda"是正确答案。
List<T> toRemove = new LinkedList<T>();
for (T t : masterList) {
  if (t.shouldRemove()) {
    toRemove.add(t);
  }
}

masterList.removeAll(toRemove);

这是一个不好的解决方案。最好使用http://docs.oracle.com/javase/6/docs/api/java/util/Iterator.html#remove()。 - Amir Raminfar

1

你可以像其他人建议的一样对索引进行排序,或者你可以使用迭代器并调用 remove() 方法

List<String> list = new ArrayList<String>();
    list.add("0");
    list.add("1");
    list.add("2");
    list.add("3");
    list.add("4");
    list.add("5");
    list.add("6");
    List<Integer> indexes = new ArrayList<Integer>();
    indexes.add(2);
    indexes.add(5);
    indexes.add(3);
    int cpt = 0;
    Iterator<String> it = list.iterator(); 
    while(it.hasNext()){
        it.next();
        if(indexes.contains(cpt)){
            it.remove();
        }
        cpt++;
    }

这取决于你的需求,但在大多数情况下,排序会更快。


我刚遇到一个情况,可以消除索引列表,因为它们只是一种记住要删除的行的解决方法。Iterator.remove很酷,可以轻松快速地解决一些删除问题。 - Stefan Steinegger

1

如果您需要删除很多元素(并且列表很长),那么迭代列表并将所有不需要删除的元素添加到新列表中可能会更快,因为 arraylist 中每个 remove() 步骤都会逐个复制被移除后的所有元素。在这种情况下,如果您的索引列表尚未排序(并且您可以与主列表并行迭代),则可能希望使用 HashSet、BitSet 或某些类似的 O(1) 访问结构来进行 contains() 检查:

/**
 * creates a new List containing all elements of {@code original},
 * apart from those with an index in {@code indices}.
 * Neither the original list nor the indices collection is changed.
 * @return a new list containing only the remaining elements.
 */
public <X> List<X> removeElements(List<X> original, Collection<Integer> indices) {
    // wrap for faster access.
    indices = new HashSet<Integer>(indices);
    List<X> output = new ArrayList<X>();
    int len = original.size();
    for(int i = 0; i < len; i++) {
       if(!indices.contains(i)) {
           output.add(original.get(i));
       }
    }
    return output;
}

1

使用guava!你要找的方法是Iterators.removeAll(Iterator removeFrom, Collection elementsToRemove)


5
我认为他手上的是指标而非真实元素,所以这对我来说没有帮助。 - whiskeysierra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接