Haritanın bir anahtar için bir değer içerip içermediğini belirleyin?


256

Bir STL haritasının belirli bir anahtar için değer içerip içermediğini belirlemenin en iyi yolu nedir?

#include <map>

using namespace std;

struct Bar
{
    int i;
};

int main()
{
    map<int, Bar> m;
    Bar b = {0};
    Bar b1 = {1};

    m[0] = b;
    m[1] = b1;

    //Bar b2 = m[2];
    map<int, Bar>::iterator iter = m.find(2);
    Bar b3 = iter->second;

}

Bunu bir hata ayıklayıcıda inceleyerek iter, sadece çöp verisi gibi görünüyor .

Bu hattı rahatsız edersem:

Bar b2 = m[2]

Ayıklayıcı gösterileri b2olduğunu {i = 0}. (Bu, tanımsız bir dizin kullanmanın tüm boş / başlatılmamış değerleri olan bir yapı döndüreceği anlamına mı geliyor?)

Bu yöntemlerin hiçbiri harika değil. Gerçekten ne gibi bir arayüz istiyorum:

bool getValue(int key, Bar& out)
{
    if (map contains value for key)
    {
        out = map[key];
        return true;
    }
    return false;
}

Bu çizgiler boyunca bir şey var mı?


Yanıtlar:


274

Bu çizgiler boyunca bir şey var mı?

Hayır. Stl map sınıfıyla, haritayı ::find()aramak ve döndürülen yineleyiciyistd::map::end()

yani

map<int,Bar>::iterator it = m.find('2');
Bar b3;
if(it != m.end())
{
   //element found;
   b3 = it->second;
}

Açıkçası isterseniz kendi getValue()rutininizi yazabilirsiniz (ayrıca C ++ 'da, kullanmak için bir neden yoktur out), ancak bir kez kullanmanın asılmasından sonra std::map::find()zamanınızı boşa harcamak istemediğinizden şüphelenirim .

Ayrıca kodunuz biraz yanlış:

m.find('2');haritada anahtar / değer çiftini arar '2'. IIRC C ++ derleyicisi '2' örtük bir int dönüştürür, bu da ASCII kodunun '2' için sayısal değeri ile sonuçlanır.

Bu örnekteki anahtar tipiniz şu intşekilde aramak istediğinizden:m.find(2);


7
Nasıl yani? findniyetin olduğundan çok daha iyi olduğunu gösterir count. Daha fazla, countöğeyi döndürmez. Eğer OP'ın soruyu okursanız, o özendirdiği için onay istiyor ediyor ve eleman dönün. findbunu yapar. countdeğil.
Alan

if (m.count (anahtar)) b3 = m [anahtar]; // ya da her neyse
pconnell

64
Ben her zaman tüm stl API tasarlayan insanlar ne tür ot sigara merak vardı.
Tuzak

2
Alan Bu konuda @dinamik ile hemfikir olmalıyım, bir yineleyici tanımlamalı ve sonra onu sonla karşılaştırmam gerekiyor, bir şey olmadığını söylemenin doğal bir yolu değil. Belirli bir öğenin bu haritada en az bir kez göründüğünü söylemek benim için çok daha basit görünüyor. Sayım da bunu yapar.
PiersyP

1
@Claudiu C ++ 20 bunu ekliyor.
pooya13

330

Harita bir çoklu harita olmadığı sürece, en zarif yollardan biri sayma yöntemini kullanmak olacaktır.

if (m.count(key))
    // key exists

Öğe haritada gerçekten mevcutsa sayı 1 olur.


22
Bu , zaten bir tane bulmuş olsa bile tüm anahtarları kontrol etmeyecek mi? Bu pahalı alabilirsiniz ...
mmdanziger

35
Bir çoklu harita üzerinde kullanıldığında yalnızca birden fazla anahtar sayar.
Temmuz

14
@mmdanziger Hayır, pahalı olmayacak: cplusplus.com/reference/map/map/count Sayı logaritmik boyuttadır.
jgyou

28
Anahtar var, sonra ne olacak? Bu noktada, genellikle başka bir arama (ör. Kullanarak operator[]) için ödeme yaparak bunun değerini elde etmek istersiniz . findsize TryGetValueneredeyse her zaman (ve özellikle OP) istediğiniz .NET semantiği verir .
Ohad Schneider

2
@serine Anladım. Anahtarın sürümde eksik olması durumunda, davranışın farklı olacağına dikkat edin, çünkü harita [anahtar] varsayılan olarak oluşturulmuş yeni bir öğe değeri döndürecektir.
Ohad Schneider

53

Sadece tam olarak söz diziminde değil, find ile zaten var.

if (m.find(2) == m.end() )
{
    // key 2 doesn't exist
}

Varsa değere erişmek istiyorsanız, şunları yapabilirsiniz:

map<int, Bar>::iterator iter = m.find(2);
if (iter != m.end() )
{
    // key 2 exists, do something with iter->second (the value)
}

C ++ 0x ve auto ile sözdizimi daha basittir:

auto iter = m.find(2);
if (iter != m.end() )
{
    // key 2 exists, do something with iter->second (the value)
}

Basitleştirmek için yeni bir mekanizma bulmaya çalışmak yerine alışmanızı tavsiye ederim. Biraz kodu azaltabilirsiniz, ancak bunu yapmanın maliyetini göz önünde bulundurun. Şimdi C ++ 'a aşina olan kişilerin tanıyamayacağı yeni bir işlev tanıttınız.

Bu uyarılara rağmen bunu yine de uygulamak istiyorsanız, o zaman:

template <class Key, class Value, class Comparator, class Alloc>
bool getValue(const std::map<Key, Value, Comparator, Alloc>& my_map, int key, Value& out)
{
    typename std::map<Key, Value, Comparator, Alloc>::const_iterator it = my_map.find(key);
    if (it != my_map.end() )
    {
        out = it->second;
        return true;
    }
    return false;
}

39

Sadece ile fark C ++ 20 , biz sahip olacak

bool std::map::contains( const Key& key ) const;

Harita anahtarlı bir öğe içeriyorsa bu doğru olur key.


Sonunda bu işlev hakkında konuşan bir cevap! (C ++ 20)
Samuel Rasquinha

En sonunda ? Teşekkürler, ama neredeyse 2 yaşında! ;-)
kebs

1
Umarım insanlar bu çözüme kayar ve artık kullanımdan kaldırılanları kullanmazlar. :)
Leśny Rumcajs

7

amap.findamap::endaradığınızı bulamadığında geri döner - bunu kontrol etmeniz gerekir.


4

Dönüş değerini kontrol findkarşı da end.

map<int, Bar>::iterator it = m.find('2');
if ( m.end() != it ) { 
  // contains
  ...
}

1

GetValue işlevinizi aşağıdaki kodla oluşturabilirsiniz:

bool getValue(const std::map<int, Bar>& input, int key, Bar& out)
{
   std::map<int, Bar>::iterator foundIter = input.find(key);
   if (foundIter != input.end())
   {
      out = foundIter->second;
      return true;
   }
   return false;
}

İnanıyorum ki satır 6 olmalıout = foundIter->second
Dithermaster

out = foundIter->secondout = *foundIter
Kip'in

1

Diğer cevaplardan bazılarını kısa ve öz olarak özetlemek için:

Henüz C ++ 20 kullanmıyorsanız, kendi mapContainsKeyişlevinizi yazabilirsiniz :

bool mapContainsKey(std::map<int, int>& map, int key)
{
  if (map.find(key) == map.end()) return false;
  return true;
}

mapVs unordered_mapve farklı anahtar ve değer türleri için birçok aşırı yüklemeden kaçınmak istiyorsanız, bunu bir templateişlev haline getirebilirsiniz .

C++ 20Veya daha yenisini kullanıyorsanız , yerleşik bir containsişlev olacaktır:

std::map<int, int> myMap;

// do stuff with myMap here

int key = 123;

if (myMap.contains(key))
{
  // stuff here
}

-1

Bir anahtarın haritada var olup olmadığını belirlemek istiyorsanız, haritanın find () veya count () üye işlevini kullanabilirsiniz. Burada kullanılan find işlevi örnekte yineleyiciyi öğeye veya map :: end öğesine döndürür. Sayma durumunda sayı 1 bulunursa 1, aksi halde sıfır (veya başka bir şekilde) döndürür.

if(phone.count(key))
{ //key found
}
else
{//key not found
}

for(int i=0;i<v.size();i++){
    phoneMap::iterator itr=phone.find(v[i]);//I have used a vector in this example to check through map you cal receive a value using at() e.g: map.at(key);
    if(itr!=phone.end())
        cout<<v[i]<<"="<<itr->second<<endl;
    else
        cout<<"Not found"<<endl;
}

-1

Boost multindex uygun çözüm için kullanılabilir. Aşağıdaki çözüm çok iyi bir seçenek değildir, ancak kullanıcının başlatma sırasında 0 veya NULL gibi varsayılan değer atadığı ve değerin değiştirilip değiştirilmediğini kontrol etmek istediği birkaç durumda yararlı olabilir.

Ex.
< int , string >
< string , int > 
< string , string > 

consider < string , string >
mymap["1st"]="first";
mymap["second"]="";
for (std::map<string,string>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
{
       if ( it->second =="" ) 
            continue;
}
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.