2011-12-23 30 views
37

Tôi mới làm quen với Qt và cố gắng tìm hiểu các thành ngữ.Làm cách nào để xóa các phần tử khỏi một Danh sách phát trong khi lặp qua các phần tử đó bằng cách sử dụng foreach?

Các foreach documentation nói:

Qt tự động chụp một bản sao của container khi nó đi vào một vòng lặp foreach. Nếu bạn sửa đổi vùng chứa khi bạn đang lặp lại, điều đó sẽ không ảnh hưởng đến vòng lặp.

Nhưng nó không nói cách để loại bỏ một yếu tố trong khi lặp lại với foreach. đoán tốt nhất của tôi là một cái gì đó như:

int idx = 0; 
foreach (const Foo &foo, fooList) { 
    if (bad(foo)) { 
    fooList.removeAt(idx); 
    } 
    ++idx; 
} 

vẻ xấu xí phải phạm vi idx bên ngoài vòng lặp (và phải duy trì một vòng lặp truy cập riêng biệt ở tất cả).

Ngoài ra, tôi biết rằng foreach tạo bản sao QList, giá rẻ nhưng điều gì sẽ xảy ra khi tôi xóa một phần tử - vẫn rẻ hoặc có bản sao sửa đổi đắt tiền đang diễn ra? Có, deep copy happens.

EDIT: Điều này dường như không phải là Qt thành ngữ.

for (int idx = 0; idx < fooList.size();) { 
    const Foo &foo = fooList[idx]; 
    if (bad(foo)) { 
    fooList.removeAt(idx); 
    } 
    else ++idx; 
} 
+1

Tại sao bạn muốn sử dụng 'foreach 'vì điều này? – Mat

+0

@Mat, tôi không phải sử dụng 'foreach', nó có vẻ tốt đẹp để sử dụng, và các tài liệu dường như đề nghị có một số cách để làm điều đó. Qt dường như đã suy nghĩ rất tốt, tôi đã tìm ra một số thành ngữ rõ ràng cho những gì tôi đang cố gắng làm. – Dan

+0

Điều gì về void QMutableListIterator :: remove()? http://developer.qt.nokia.com/doc/qt-4.8/qmutablelistiterator.html#remove –

Trả lời

38

Bạn nên tốt hơn use iterators cho rằng:

// Remove all odd numbers from a QList<int> 
QMutableListIterator<int> i(list); 
while (i.hasNext()) { 
    if (i.next() % 2 != 0) 
     i.remove(); 
} 
+2

Tài liệu nói "chuẩn trong ứng dụng Qt ... thuận tiện hơn STL ... hơi kém hiệu quả". OK, 2 trong số 3 không phải là xấu. Cảm ơn bạn! – Dan

16

Nếu bạn không muốn có một bản sao ở tất cả, sử dụng vòng lặp. Một cái gì đó như:

QList<yourtype>::iterator it = fooList.begin(); 
while (it != fooList.end()) { 
    if (bad(*it)) 
    it = fooList.erase(it); 
    else 
    ++it; 
} 

(Và chắc chắn rằng bạn thực sự muốn sử dụng một QList thay vì một QLinkedList.)

foreach thực sự thoải mái khi bạn muốn đi qua một bộ sưu tập để kiểm tra, nhưng khi bạn đã tìm thấy , thật khó để lý do khi bạn muốn thay đổi cấu trúc của bộ sưu tập cơ bản (không phải các giá trị được lưu trữ trong đó). Vì vậy, tôi tránh nó trong trường hợp đó, đơn giản bởi vì tôi không thể tìm ra nếu nó là an toàn hoặc bao nhiêu sao chép trên không xảy ra.

+0

Bạn không nên sợ sử dụng QList thay vì QLinkedList trong hầu hết các trường hợp. QList thực sự lưu trữ tất cả các phần tử của nó cũng như con trỏ. Như vậy, phụ thêm, chèn hoặc xóa các phần tử không đắt như trong QVector. – UndeadKernel

8

Nếu chức năng kiểm tra là lõm, bạn cũng có thể sử dụng QtConcurrent để loại bỏ các "xấu" yếu tố:

#include <QtCore/QtConcurrentFilter> 
... 
QtConcurrent::blockingFilter(fooList, bad); 

Hoặc biến STL:

#include <algorithm> 
... 
fooList.erase(std::remove_if(fooList.begin(), fooList.end(), bad), 
       fooList.end());