2012-07-27 38 views
6

Giả sử tôi muốn xóa các mục theo một số tiêu chí. Giả sử:Làm cách nào để xóa các giá trị khỏi QMap?

QMap<int, int> map; 

và tôi muốn xóa tất cả các mục có giá trị là số lẻ. Nếu tôi sử dụng một iterator:

for (auto it = map.begin(); it != map.end(); ++it) 
    if (it.value() % 2 == 1) 
     map.remove(it.key()); 

Mã này có lẽ là sai, vì tiếng gọi của

map.remove(it.key()) 

làm mất hiệu lực iterator. Làm thế nào tôi có thể làm điều này mà không cần thiết lập lại các iterator sau mỗi loại bỏ?

+2

Điều này sẽ giúp tôi nghĩ rằng: http://stackoverflow.com/questions/263945/what-happens-if-you-call-erase-on-a-map-element-while-iterating-from-begin-to – Andrew

Trả lời

16

Sử dụng QMap::erase thay vào đó, mà trả về một iterator để các phần tử sau khi bạn vừa bị xóa:

for (auto it = map.begin(); it != map.end();) 
    if (it.value() % 2 == 1) 
     it = map.erase(it); 
    else 
     ++it; 

Một cách khác là sử dụng postfix increment điều hành trên iterator:

for (auto it = map.begin(); it != map.end();) 
    if (it.value() % 2 == 1) 
     map.erase(it++); 
    else 
     ++it; 

Tuy nhiên, một cách khác (và có thể kém hiệu quả hơn) là sử dụng thuật toán STL remove_copy_if, theo sau là swap:

bool valueIsOdd(int value) {return value % 2 == 1;} 

QMap<int,int> b; 
std::remove_copy_if(a.begin(), a.end(), 
        std::inserter(b, b.end()), 
        &valueIsOdd); 
a.swap(b); 

Tôi không thể kiểm tra ví dụ cuối cùng vào lúc này.

+2

Bạn chỉ nên tăng 'it' nếu bạn không xóa phần tử; nếu không, bạn sẽ bỏ lỡ yếu tố tiếp theo. –

+0

Rất tiếc! Đã sửa. Cảm ơn. –

+0

Hoặc chỉ sử dụng [QMutableMapIterator] (http://doc.qt.io/qt-5/qmutablemapiterator.html#details). –

4

Bạn sẽ khấm khá hơn bằng cách sử dụng STL-like hơn erase chức năng:

  • Phải mất một iterator như một cuộc tranh cãi, và vì vậy không lãng phí thời gian tìm kiếm các phần tử của chính nó khi bạn đã biết Nó ở đâu vậy;
  • Nó trả về một trình lặp cho phần tử tiếp theo, vì vậy bạn có thể tiếp tục lặp lại sau đó.

Sử dụng này, bạn có thể thực hiện vòng lặp của bạn một cách chính xác như:

for (auto it = map.begin(); it != map.end(); /* don't increment here */) { 
    if (it.value() % 2 == 1) { 
     it = map.erase(it); 
    } else { 
     ++it; 
    } 
} 

Tôi nghĩ rằng bạn có thể nhận được kết quả tương tự từ map.remove((it++).key()), nhưng điều đó sẽ được cả hai chậm hơn và Messier hơn erase.

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