【问题标题】:Remove objects from an ArrayList based on a given criteria根据给定条件从 ArrayList 中删除对象
【发布时间】:2012-10-30 06:40:16
【问题描述】:

如果满足特定条件,我想从 Java 中的 ArrayList 中删除一个元素。

即:

for (Pulse p : pulseArray) {
    if (p.getCurrent() == null) {
        pulseArray.remove(p);
    }
}

我可以理解为什么这不起作用,但是有什么好的方法可以做到这一点?

【问题讨论】:

  • 这不仅会失败,而且即使它确实有效,它的性能也会很糟糕。这是一种 O(n^2) 算法,因为您必须检查数组的每个元素,直到要删除的元素。最优算法是 O(n)。
  • @MarkByers“检查数组的每个元素”是O(n),为什么你认为这是O(n^2)?
  • @jlordo: list.remove(object) 是一个 O(n) 操作。它被执行 O(n) 次,因为它处于循环中。这给出了 O(n*n)。
  • @MarkByers 谢谢。我认为remove(Object) 是 O(1),但文档证明了你的观点。

标签: java arraylist


【解决方案1】:

你可以使用Collection::removeIf(Predicate filter)(从Java8开始可用),这里是一个简单的例子:

final Collection<Integer> list = new ArrayList<>(Arrays.asList(1, 2));
list.removeIf(value -> value < 2);
System.out.println(list); // outputs "[2]"

【讨论】:

  • 如果您想支持旧的 API,请不要使用它。在 4.4 上因 NoClassDefFoundError 而崩溃。
  • @Sagar,我添加了一个提示。
【解决方案2】:

您必须使用Iterator 进行迭代,并使用迭代器的remove 函数(不在列表中):

Iterator<Pulse> iter = pulseArray.iterator();
while (iter.hasNext()) {
  Pulse p = iter.next();
  if (p.getCurrent()==null) iter.remove();
}

请注意,Iterator#remove 函数据说是可选的,但它由 ArrayList 的迭代器实现的。

这是 ArrayList.java 中这个具体函数的代码:

765         public void remove() {
766             if (lastRet < 0)
767                 throw new IllegalStateException();
768             checkForComodification();
769 
770             try {
771                 ArrayList.this.remove(lastRet);
772                 cursor = lastRet;
773                 lastRet = -1;
774                 expectedModCount = modCount;
775             } catch (IndexOutOfBoundsException ex) {
776                 throw new ConcurrentModificationException();
777             }
778         }
779 
780         final void checkForComodification() {
781             if (modCount != expectedModCount)
782                 throw new ConcurrentModificationException();
783         }
784     }

expectedModCount = modCount; 行是为什么在迭代时使用它时它不会抛出异常的原因。

【讨论】:

  • 从技术上讲,增强的for循环使用迭代器。你能举一个他必须做什么的例子吗?此外,应该注意的是,并非所有迭代器都会真正实现 remove 方法,并且会抛出“未实现”异常。
  • @Clockwork-Muse 是的,但内部 ArrayList 的迭代器确实实现了它。
【解决方案3】:

无需使用迭代器。使用 Java 8(流式传输和过滤功能以及 lambda),您可以使用一行来完成它。 例如。执行您指定的操作所需的代码将是:

pulseArray = pulseArray.stream().filter(pulse -> pulse != null).collect(Collectors.toList());

【讨论】:

  • 你也可以使用Objects::nonNull
  • 不应该是... -&gt; pulse.getCurrent() != null)...
【解决方案4】:

当您从同一列表删除元素时,索引会受到干扰。尝试以下不同的方式:

  for (int i=0; i < pulseArray.size(); i++) {
     Pulse p = (Pulse)pulseArray.get(i);
     if (p.getCurrent() == null) {
        pulseArray.remove(p);
        i--;//decrease the counter by one
     }
  }

【讨论】:

    【解决方案5】:

    作为使用迭代器的替代方法,您可以使用Guava 集合库。这样做的好处是更多functional(如果你喜欢那种东西):

    Predicate<Pulse> hasCurrent = new Predicate<Pulse>() {
      @Override public boolean apply(Pulse input) {
        return (input.getCurrent() != null);
      }
    };
    
    pulseArray = Lists.newArrayList(Collections2.filter(pulseArray, hasCurrent));
    

    【讨论】:

      【解决方案6】:

      你可以实现接口Predicate覆盖抽象方法boolean test(T);

      使用 removeIf(Predicate p) 方法从你的 列表。

      例如:

      List<Book> bookList = new ArrayList<>();
      bookList.add(new Book(101, "bookname1"));
      bookList.add(new Book(102, "booknamelong2"));
      bookList.removeIf(new LongBookNames())
      
      public class LongBookNames implements Predicate<Book> {
      
        @Override
        public boolean test(Book book) {
          return book.getBookName.length() >10;
        }
      }
      

      【讨论】:

        【解决方案7】:

        您不能使用集合上的方法更改正在迭代的集合。但是,某些迭代器(包括 ArrayLists 上的迭代器)支持 remove() 方法,该方法允许您按照迭代顺序删除方法。

        Iterator<Pulse> iterator = pulseArray.iterator();
        while (iterator.hasNext()) {
          Pulse p = iterator.next();
          if (p.getCurrent() == null) {
            iterator.remove();
          }
        }
        

        【讨论】:

          【解决方案8】:

          当 Single ArrayList 有多种类型的 Objects 并且一个对象的 count == 0 时使用以下一个,然后将其从 pulseArray

          中删除

          Constants.java

          public class ViewType {
              public static final int PULSE = 101;
              public static final int HEARTBEAT = 102;
          }
          

          BaseModel.java(这是基础模型)

          public interface BaseModel {
              int getViewType();
          }
          

          PulseModel.java(使用 BaseModel 实现)

          public class PulseModel implements BaseModel {
          
              @Override
              public int getViewType() {
                  return Constants.ViewType.PULSE;
              }
          
              @SerializedName("PulseId")
              @Expose
              private String pulseId;
              @SerializedName("Count")
              @Expose
              private String count;
          }
          

          pulseArray 中移除 Count = 0

          的 PulseModel 对象
          pulseArray.removeIf(
               (BaseModel model) -> {
                   boolean remove = false;
                   if (model instanceof PulseModel) {
                        remove = (((PulseModel) model).getCount() == 0);
                        if (remove) {
                           //Success
                        }
                   }
                   return remove;
                });
          

          【讨论】:

            【解决方案9】:

            使用迭代器可以让您在遍历数组列表时修改列表

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2014-02-06
              • 2023-03-07
              • 1970-01-01
              • 2021-03-11
              • 2015-08-02
              相关资源
              最近更新 更多