【问题标题】:Java Arraylist remove multiple element by indexJava Arraylist 按索引删除多个元素
【发布时间】:2015-04-15 16:45:31
【问题描述】:

这是我的代码:

for (int i = 0; i < myarraylist.size(); i++) {
        for (int j = 0; j < stopwords.size(); j++) {
            if (stopwords.get(j).equals(myarraylist.get(i))) {
                myarraylist.remove(i);
                id.remove(i);
                i--; // to look at the same index again!
            }
        }
    }

我有问题..删除元素后,所有索引总是改变,上面的循环太乱了。

为了说明: 我有 54 条数据,但在删除元素后,上面的循环变得混乱。所以只有 50 条数据被检查。

还有其他方法或修复我的代码以按索引删除多个元素?? 元素索引对我来说非常重要,要删除另一个具有相同索引的数组列表。

【问题讨论】:

标签: java android arraylist stop-words


【解决方案1】:

您需要记住的一件事是,当您使用 ArrayLists 时,它们应该是通用的,而不是 Arrays。您可以通过删除整个索引来缩短数组,向其添加索引,并使用ArrayLists 做精彩的事情。

对于那些没有意识到或不记得,当您删除一个值时,ArrayList 索引(或任何正确的复数形式)会重新调整,ArrayList 会缩短,这是一个常见问题。

尝试从ArrayList 中删除元素时,您应该始终从ArrayList 的末尾开始。

for(int x = arrayList.size() - 1; x > 0; x--)
{
    arrayList.remove(x);
}

这应该为您提供您正在寻找的功能。查看ArrayList API 了解其他可能对您有所帮助的方法。

【讨论】:

  • @SteveKuo,为什么? x 应该是 x = arrayList.size() - 1。我实际上并没有考虑过检查,我只是想向 OP 展示从数组列表中删除元素的做法。
  • 你是对的,你落后了。一般来说,使用 Iterator 的 remove 比依赖基于逆序索引的循环要好得多。
  • @SteveKuo 感谢发现伙伴,改变了它。没听说过迭代器,猜猜是时候研究一下了。
  • 考虑到性能,这不是一个好的解决方案。 arrayList.remove(index) remove() 方法将移动其他后续元素。
  • 此解决方案在以下数据上失败。 data = [5,2,7,3,9,34,63,23,85,23,94,7] int index[] = [5,2,7,9] // 要删除的索引
【解决方案2】:

使用Iterator.remove() 在迭代时删除元素。

for (Iterator<String> iter = myarraylist.iterator(); iter.hasNext(); ) {
  String element = iter.next();
  if (element meets some criteria) {
    iter.remove();
  }
}

或使用 Google Guava 的 filter,它会返回过滤后的视图并保持原始列表不变。

Iterable<String> filtered = Iterables.filter(myarraylist, new Predicate<String>() {
  public boolean apply(String element) {
    return true of false based on criteria
  }
});

【讨论】:

    【解决方案3】:

    好的,这是一个很好解决的问题。 让我们从一个例子开始

    我们有data = [5,2,7,3,9,34,63,23,85,23,94,7]

    要删除的索引

    int index[] = [5,2,7,9]
    

    注意:当您从数组中删除单个项目时,其他元素会移动 1。

    如果我们使用 ArrayList 来删除索引的元素,那么首先你需要对索引进行降序排序。

    即索引 = [9,7,5,2] 然后从索引中删除元素

    ArrayList<Integer> data = Arrays.asList(new Integer[] {5,2,7,3,9,34,63,23,85,23,94,7});
    
    for(int i=0;i<index.length;i++){
        data.remove(index[i]);
        }
    

    【讨论】:

      【解决方案4】:

      看起来你想从另一个集合中删除一个集合。你应该使用 改用 java.util.Collection#removeAll 方法

      【讨论】:

        【解决方案5】:

        不确定为什么要按索引执行此操作,但您可以试试这个(未经测试):

        int dynamicSize = myarraylist.size();
        for (int i = 0; i < dynamicSize; i++) {
                for (int j = 0; j < stopwords.size(); j++) {
                    if (stopwords.get(j).equals(myarraylist.get(i))) {
                        myarraylist.remove(i);
                        id.remove(i);
                        i--; // to look at the same index again!
                        dynamicSize--;
                    }
                }
            }
        

        【讨论】:

          【解决方案6】:

          在迭代列表时,您正在删除对象使用迭代器。

          Iterator myListItr = myarraylist.iterator();
          //Iterate on list 
              while(myListItr .hasNext()) {
              //if stop words is list of string then contains will work as it is. If its your custom object then override equals method.
                  if(stopwords.contains( myListItr.next())){
              myListItr.remove();
          }
          }
          

          【讨论】:

            【解决方案7】:

            使用ListIterator

            ArrayList<String> list = new ArrayList<String>();
                  // List : ["java", ".net", "javascript", "html", "css", "selenium", "image", "Spring"]
            
                ArrayList<Integer> indexes = new ArrayList<Integer>();
                                                  // indexes : [5, 3, 2, 5, 0]
                // Sort the Indexes in Order to remove from back words. and make Unique
                TreeSet<Integer> uniqueSorted = new TreeSet<Integer>();
                    uniqueSorted.addAll(indexes);
            
                // To remove all elements from the ArrayList and make its size = 0  
                    indexes.clear(); 
                    indexes.addAll(uniqueSorted);
            
                // Iterate form back, so that if size decreases also no problem.
                ListIterator<Integer> li = indexes.listIterator(indexes.size());
            
               // we can traverse a List in both the directions (forward and Backward).
                    while(li.hasPrevious()) {
                        int position = li.previous();
                        list.remove(position);
                    }
            

            【讨论】:

              【解决方案8】:

              这是一个简短的基准,粗略地比较了从数组列表中删除元素的各种方法。按索引删除确实是个坏主意,因为数组列表在每次操作时都会缩小其内部数组。小型数组不会有真正的区别,但是如果您要删除大量索引,则成本会很高。

              Benchmark                                    Mode  Cnt   Score   Error  Units
              CollectionsTest.filterToNewListViaLoop       avgt    2   4.425          ms/op
              CollectionsTest.filterToNewListViaStream     avgt    2   5.410          ms/op
              CollectionsTest.removeByIndexInReverseOrder  avgt    2  69.234          ms/op
              CollectionsTest.removeByIterator             avgt    2   4.311          ms/op
              CollectionsTest.removeViaRemoveAllMethod     avgt    2   4.145          ms/op
              

              代码:

              @BenchmarkMode(Mode.AverageTime)
              @OutputTimeUnit(MILLISECONDS)
              @State(Scope.Benchmark)
              @Warmup(iterations = 2)
              @Measurement(iterations = 2)
              public class CollectionsTest {
              
                  private static final Random RANDOM = new Random();
                  private static final int CONTAINER_SIZE = 100_000;
                  private static final int REMOVE_COUNT = 10_000;
              
                  private List<Foo> _container;
                  private TreeSet<Integer> _indicesToRemove;
                  private HashSet<Foo> _elementsToRemove;
              
                  public static void main(String[] args) throws RunnerException {
                      Options opt = new OptionsBuilder()
                              .include(CollectionsTest.class.getSimpleName())
                              .forks(1)
                              .build();
                      new Runner(opt).run();
                  }
              
                  @Setup(Level.Invocation)
                  public void setup() {
                      _container = generateContainerData(CONTAINER_SIZE);
                      _indicesToRemove = generateIndicesToRemove(REMOVE_COUNT, CONTAINER_SIZE);
              
                      _elementsToRemove = new HashSet<>();
                      _indicesToRemove.stream().map(Foo::new).forEach(_elementsToRemove::add);
                  }
              
                  @Benchmark
                  public void removeByIndexInReverseOrder() {
                      int iterations = 0;
                      for (int arrayIndex : _indicesToRemove.descendingSet()) {
                          _container.remove(arrayIndex);
                      }
                  }
              
                  @Benchmark
                  public void removeByIterator() {
                      _container.removeIf(foo -> _elementsToRemove.contains(foo));
                  }
              
                  @Benchmark
                  public void filterToNewListViaStream() {
                      List<Foo> elementsToKeep = _container.stream()
                              .filter(foo -> !_indicesToRemove.contains(foo.id))
                              .collect(Collectors.toList());
                  }
              
                  @Benchmark
                  public void filterToNewListViaLoop() {
                      List<Foo> elementsToKeep = new ArrayList<>(CONTAINER_SIZE - REMOVE_COUNT);
                      for (Foo foo : _container) {
                          if (!_indicesToRemove.contains(foo.id)) elementsToKeep.add(foo);
                      }
                  }
              
                  @Benchmark
                  public void removeViaRemoveAllMethod() {
                      _container.removeAll(_elementsToRemove);
                  }
              
                  private List<Foo> generateContainerData(int size) {
                      List<Foo> data = new ArrayList<>();
                      for (int idx = 0; idx < size; idx++) {
                          data.add(new Foo(idx));
                      }
                      return data;
                  }
              
                  private TreeSet<Integer> generateIndicesToRemove(int count, int containerSize) {
                      TreeSet<Integer> data = new TreeSet<>();
                      ThreadLocalRandom.current().ints(0, containerSize)
                              .distinct()
                              .limit(count)
                              .forEach(data::add);
                      return data;
                  }
              
                  public static class Foo implements Comparable<Foo> {
                      private static final Comparator<Foo> COMPARATOR = Comparator.comparing(foo -> foo.id);
              
                      public int id;
              
                      public Foo(int id) {
                          this.id = id;
                      }
              
                      @Override
                      public int compareTo(Foo that) {
                          return COMPARATOR.compare(this, that);
                      }
              
                      @Override
                      public String toString() {
                          final StringBuilder sb = new StringBuilder("Foo{");
                          sb.append("id=").append(id);
                          sb.append('}');
                          return sb.toString();
                      }
                  }
              }
              

              【讨论】: