Std :: multiset'te, bir öğe bulunursa yalnızca bir örneği (tek veya çift) silmek için bir işlev veya algoritma var mı


83

Belki de bu bir kopya ama arama yapan bir şey bulamadım: Çağrıldığında erase(value), std::multisetbulunan değere sahip tüm elemanlar silinir. Aklıma gelen tek çözüm şudur:

std::multiset<int>::iterator hit(mySet.find(5));
if (hit!= mySet.end()) mySet.erase(hit);

Sorun değil ama daha iyi olabileceğini düşündüm. Herhangi bir fikir ?


22
Bu tamamen makul bir yaklaşımdır.
templatetypedef

Bu yaklaşım verilen anahtarın ("5") yinelenmesini sağlıyor mu?
Arun

@ArunSaha: Hayır. Ama kopyası değilse onu yine de silmek istiyorum. Aldığım cevaplardan daha iyi bir çözüm olmadığı hissine kapılıyorum. Belki de soru ilk etapta aptalcaydı :-P
Martin

1
İçin multimap: Hangi unsurlar üzerinde herhangi garantisi yoktur findgetiri? (
Yerleştirme sırası

2
Dürüst olmak gerekirse, en sık kullanılan sınıflar arasında olmayan multiset'i kullanırken bu çok açık bir tuzak.
Predelnik

Yanıtlar:


31
auto itr = my_multiset.find(value);
if(itr!=my_multiset.end()){
    my_multiset.erase(itr);
}

Ben de aynısını yapmanın daha temiz bir yolu olduğunu düşünürdüm. Ama bu işi halleder.


10
Bu, söz konusu olandan farklı değil.
Troubadour

2
Katılıyorum! Hiç mantıklı değil. Diğer 12 kişi cevapta faydalı bir şey gördü, bu yüzden delirmediğimi biliyorum.
user2251346

8
Herkesle birlikte delirme olasılığını asla göz ardı etme :)
Apollys Monica'yı destekliyor

16

Bunu dene:

multiset<int> s;
s.erase(s.lower_bound(value));

valueSette çıkışların olmasını sağlayabildiğiniz sürece . Bu çalışır.


2
 if(my_multiset.find(key)!=my_multiset.end())
   my_multiset.erase(my_multiset.equal_range(key).first);

Bu, c ++ 'da bir çoklu kümedeki tek bir örneği kaldırmanın en iyi yolu


1
Soruda önerdiğim çözüme kıyasla, kodunuz verimsiz bir arama yerine iki arama yapıyor (bul + eşit_aralık)
Martin

bu aynı karmaşıklık olduğundan, bu yanıtı çok beğendim. Teşekkürler
Crystal

1

Aşağıdakileri denerim.

İlk equal_range()olarak anahtara eşit eleman aralığını bulmak için arama yapın.

Döndürülen aralık boş değilse, erase()bir dizi öğe (yani erase()iki yineleyici alan):

  • ilk bağımsız değişken, döndürülen aralıktaki 2. öğenin yineleyicisidir (yani, geçmişte bir .firstdöndürülür) ve

  • döndürülen aralık çifti yineleyicisi olarak ikinci bağımsız değişken .second.


Templatetypedef'in (Teşekkürler!) Yorumunu okuduktan sonra düzenleyin :

Bir (hepsinin tersine) yinelemenin kaldırılması gerekiyorsa: Döndürülen çift equal_range()en az iki öğeye sahipse erase(), ilk öğe döndürülen çiftin ilkini aşağıdakilerin tek yineleyici sürümüne geçirerek erase():

Sözde kod:

pair<iterator, iterator> pit = mymultiset.equal_range( key );

if( distance( pit.first, pit.second ) >= 2 ) {
    mymultiset.erase( pit.first );
}

2
Sanırım soru, tüm kopyaları değil, yalnızca bir kopyayı ortadan kaldırmakla ilgili.
templatetypedef

Bunun benim çözümümden daha hızlı olup olmadığına dair bir fikriniz var mı ve evet ise neden?
Martin

1

Bu benim için çalıştı:

multi_set.erase(multi_set.find(val));

çoklu kümede val varsa.


0

Bunun gibi bir şey yapabiliriz:

multiset<int>::iterator it, it1;
it = myset.find(value);
it1 = it;
it1++;
myset.erase (it, it1);

1
Aşırı yükleme. "Yineleyici, unordered_multiset'ten kaldırılacak tek bir öğeyi işaret ediyor."
Andrew

0
 auto itr=ms.find(value);  
  while(*itr==value){
  ms.erase(value);
  itr=ms.find(value);  
  }

Bunu deneyin Çoklu kümede bulunan tüm kopyaları kaldıracaktır.


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.