Saya mencoba menghapus berbagai elemen dari peta berdasarkan kondisi tertentu. Bagaimana cara melakukannya menggunakan algoritma STL?
Awalnya saya berpikir untuk menggunakan remove_if
tetapi tidak mungkin karena remove_if tidak berfungsi untuk wadah asosiatif.
Apakah ada algoritme setara "remove_if" yang berfungsi untuk peta?
Sebagai opsi sederhana, saya berpikir untuk mengulang melalui peta dan menghapus. Tetapi apakah perulangan melalui peta dan menghapus opsi yang aman? (Karena iterator menjadi tidak valid setelah dihapus)
Saya menggunakan contoh berikut:
bool predicate(const std::pair<int,std::string>& x)
{
return x.first > 2;
}
int main(void)
{
std::map<int, std::string> aMap;
aMap[2] = "two";
aMap[3] = "three";
aMap[4] = "four";
aMap[5] = "five";
aMap[6] = "six";
// does not work, an error
// std::remove_if(aMap.begin(), aMap.end(), predicate);
std::map<int, std::string>::iterator iter = aMap.begin();
std::map<int, std::string>::iterator endIter = aMap.end();
for(; iter != endIter; ++iter)
{
if(Some Condition)
{
// is it safe ?
aMap.erase(iter++);
}
}
return 0;
}
for(auto iter=aMap.begin(); iter!=aMap.end(); ){ ....}
untuk mengurangi kekacauan. Istirahat seperti yang dikatakan orang lain. Pertanyaan ini menyelamatkan saya dari beberapa masalah sekarang ;-)Jawaban:
Hampir.
Apa yang Anda semula akan menambah iterator dua kali jika Anda benar-benar menghapus elemen darinya; Anda berpotensi melewatkan elemen yang perlu dihapus.
Ini adalah algoritma umum yang pernah saya lihat digunakan dan didokumentasikan di banyak tempat.
[EDIT] Anda benar bahwa iterator tidak valid setelah penghapusan, tetapi hanya iterator yang mereferensikan elemen yang dihapus, iterator lain masih valid. Karenanya menggunakan
iter++
dalamerase()
panggilan.sumber
map
, kembalikan iterator berikutnya darierase(iter)
. Jauh lebih bersih untuk dilakukaniter = erase( iter )
.erase_if untuk std :: map (dan penampung lainnya)
Saya menggunakan template berikut untuk hal ini.
Ini tidak akan mengembalikan apa pun, tetapi akan menghapus item dari std :: map.
Contoh penggunaan:
Contoh kedua (memungkinkan Anda untuk meneruskan nilai tes):
sumber
std
. Saya mengerti mengapa itu bukan anggotastd::map
, tetapi saya pikir sesuatu seperti itu harus ada di perpustakaan standar.std::map
dan lainnya.Sekarang,
std::experimental::erase_if
tersedia di header<experimental/map>
.Lihat: http://en.cppreference.com/w/cpp/experimental/map/erase_if
sumber
Dokumentasi ini saya dapatkan dari referensi SGI STL yang sangat baik :
Jadi, iterator yang Anda miliki yang mengarah ke elemen yang akan dihapus tentu saja tidak valid. Lakukan sesuatu seperti ini:
sumber
erase
dipanggil. Jadi mereka memang setara. Namun, saya lebih memilih versi Anda daripada yang asli.Kode asli hanya memiliki satu masalah:
Di sini,
iter
bertambah sekali dalam perulangan for dan waktu lain dalam penghapusan, yang mungkin akan berakhir dalam beberapa perulangan tak terbatas.sumber
Inilah beberapa solusi elegan.
sumber
Dari catatan bawah:
http://www.sgi.com/tech/stl/PairAssociativeContainer.html
Pair Associative Container tidak dapat menyediakan iterator yang dapat diubah (seperti yang didefinisikan dalam persyaratan Trivial Iterator), karena tipe nilai dari iterator yang dapat berubah harus dapat ditetapkan, dan pasangan tidak dapat ditetapkan. Namun, Pair Associative Container dapat menyediakan iterator yang tidak sepenuhnya konstan: iterator sedemikian rupa sehingga ekspresi (* i) .second = d valid.
sumber
Pertama
Kedua, kode berikut ini bagus
Saat memanggil suatu fungsi, parameter dievaluasi sebelum panggilan ke fungsi itu.
Jadi, ketika iter ++ dievaluasi sebelum panggilan untuk dihapus, operator ++ dari iterator akan mengembalikan item saat ini dan akan menunjuk ke item berikutnya setelah panggilan.
sumber
IMHO tidak ada yang
remove_if()
setara.Anda tidak dapat menyusun ulang peta.
Jadi
remove_if()
tidak bisa menempatkan pasangan Anda di akhir yang dapat Anda panggilerase()
.sumber
Berdasarkan jawaban Iron Savior Bagi mereka yang ingin memberikan lebih banyak rentang di sepanjang garis iterator pengambilan fungsional std.
Penasaran apakah ada cara untuk kehilangan
ContainerT
item dan mendapatkannya dari iterator.sumber
Jawaban Steve Folly saya rasa lebih efisien.
Berikut adalah solusi lain yang mudah tetapi kurang efisien :
Solusi yang digunakan
remove_copy_if
untuk menyalin nilai yang kita inginkan ke dalam wadah baru, lalu menukar isi wadah asli dengan yang baru:sumber
Jika Anda ingin menghapus semua elemen dengan kunci lebih besar dari 2, maka cara terbaik adalah
Hanya berfungsi untuk rentang, bukan untuk predikat apa pun.
sumber
Saya menggunakan seperti ini
sumber