2012-11-09 28 views
7

Tôi muốn xóa phần tử khỏi ArrayList trong Java nếu đáp ứng một tiêu chí nhất định.Xóa đối tượng khỏi ArrayList dựa trên tiêu chí đã cho

ví dụ:

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

tôi có thể hiểu tại sao điều này không làm việc, nhưng một cách tốt để làm điều này là gì?

+0

Không chỉ này sẽ thất bại để làm việc, nhưng ngay cả khi nó đã làm việc nó sẽ có hiệu suất khủng khiếp. Đó là một thuật toán O (n^2) bởi vì bạn phải kiểm tra mọi phần tử của mảng lên đến phần tử bạn đang xóa. Thuật toán tối ưu là O (n). –

+0

@MarkByers "kiểm tra mọi phần tử của mảng" là O (n), tại sao bạn nghĩ đây là O (n^2)? – jlordo

+0

@jlordo: 'list.remove (đối tượng)' là một hoạt động O (n). Nó được thực hiện O (n) lần vì nó trong một vòng lặp. Điều đó cho O (n * n). –

Trả lời

11

Bạn phải sử dụng một Iterator để lặp và remove chức năng của iterator (không danh sách):

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

Lưu ý rằng chức năng Iterator#remove được cho là optionnal nhưng nó được thực hiện bởi Trình lặp của ArrayList.

Dưới đây là đoạn code của chức năng cụ thể này từ 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  } 

Dòng expectedModCount = modCount; là lý do tại sao nó sẽ không ném một ngoại lệ khi bạn sử dụng nó trong khi iterating.

+0

Về mặt kỹ thuật, _is_ tăng cường cho vòng lặp sử dụng một trình lặp. Bạn có thể đưa ra một ví dụ về những gì anh ta phải làm? Ngoài ra, cần lưu ý rằng không phải tất cả các trình vòng lặp sẽ thực sự thực hiện phương thức remove và sẽ ném một ngoại lệ 'không được thực hiện'. –

+0

@ Clockwork-Muse Có nhưng trình lặp nội bộ của ArrayList thực hiện nó. –

0

Bạn không thể thay đổi bộ sưu tập mà bạn đang lặp lại bằng cách sử dụng các phương pháp trên bộ sưu tập. Tuy nhiên, một số trình lặp (bao gồm các trình vòng lặp trên ArrayList s) hỗ trợ phương thức remove() cho phép bạn loại bỏ các phương thức theo thứ tự mà bạn đang lặp lại.

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

Khi bạn đang loại bỏ các yếu tố từ cùng một danh sách, chỉ số bị quấy rầy. Hãy thử chút khác nhau như sau:

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 
    } 
    } 
-1

Sử dụng một Iterator sẽ cung cấp cho bạn sức mạnh để sửa đổi danh sách trong khi lặp qua ArrayList

2

Là một phai lạt để sử dụng một iterator, bạn có thể sử dụng thư viện Guava bộ sưu tập. Điều này có lợi thế là hơn functional (nếu bạn là thành rằng loại điều):

Predicate<Pulse> hasCurrent = new Predicate<Pulse>() { 
    @Override public boolean apply(Pulse input) { 
    return (input.getCurrent() != null); 
    } 
}; 

pulseArray = Lists.newArrayList(Collections2.filter(pulseArray, hasCurrent)); 
1

Không cần phải sử dụng lặp. Với Java 8 (khả năng phát trực tuyến và lọc và lambdas), bạn có thể thực hiện nó bằng một dòng. Ví dụ: mã cần thiết mà không hoạt động mà bạn chỉ định sẽ là:

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

Bạn nên sử dụng 'removeIf' thay vì tạo danh sách mới ... – assylias

+0

Bạn cũng có thể sử dụng' Objects :: nonNull'. – shmosel

1

Bạn có thể sử dụng Collection::removeIf(Predicate filter), đây là một ví dụ đơn giản:

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

Điều này phù hợp với tôi –

Các vấn đề liên quan