Cómo encontrar si una clave dada existe en un C ++ std :: map


450

Estoy tratando de verificar si una clave dada está en un mapa y de alguna manera no puedo hacerlo:

typedef map<string,string>::iterator mi;
map<string, string> m;
m.insert(make_pair("f","++--"));
pair<mi,mi> p = m.equal_range("f");//I'm not sure if equal_range does what I want
cout << p.first;//I'm getting error here

Entonces, ¿cómo puedo imprimir lo que está en p?


std::pair<iterator,bool> insert( const value_type& value );¿Cuál es el bool que devuelve? ¿dice si la clave ya está presente o no?
krithikaGopalakrisnan

Respuestas:


691

Utilizar map::find

if ( m.find("f") == m.end() ) {
  // not found
} else {
  // found
}

105
Si solo desea verificar si existe una clave determinada, probablemente map::count
prefiera

10
@tomsmeding Solo hay una clave en un std :: map. Entonces el conteo será 0 o 1. ¿Es uno más eficiente que el otro?
goelakash

34
@goelakash apenas; es solo que countdevuelve un inttiempo finddevuelve un iterador completo. Guarda la construcción del iterador :) Obviamente, si luego va a usar el valor si existe, use find y almacene su resultado.
tomsmeding

99
@tomsmeding Si está utilizando un mapa múltiple, tendría que revisar todo el contenedor. En cuyo caso, find () puede ser más rápido.
Trevor Hickey

11
Para aquellos que buscan velocidad: count y findson casi idénticos en velocidad cuando usan mapas que requieren claves únicas. (1) Si no necesita los elementos para mantener un orden específico, use std :: unordered_map , que tiene búsquedas casi constantes y puede ser muy beneficioso al almacenar más de unos pocos pares. (2) Si desea usar el valor si existe, almacene el resultado de :: find y use el iterador para evitar 2 búsquedas:auto it = m.find("f"); if (it != m.end()) {/*Use it->second*/}
cdgraham

305

Para verificar si existe una clave particular en el mapa, use la countfunción miembro de una de las siguientes maneras:

m.count(key) > 0
m.count(key) == 1
m.count(key) != 0

La documentación de map::finddice: "Otra función miembro map::count, puede usarse para verificar si existe una clave en particular".

La documentación de map::countdice: "Debido a que todos los elementos en un contenedor de mapas son únicos, la función solo puede devolver 1 (si se encuentra el elemento) o cero (de lo contrario)".

Para recuperar un valor del mapa a través de una clave que sabe que existe, use map :: at :

value = m.at(key)

A diferencia de map :: operator [] , map::atno creará una nueva clave en el mapa si la clave especificada no existe.


33
Si va a hacer ambas operaciones, verifique si existe y luego haga algo al respecto. Usar en su findlugar. El secondatributo del iterador devuelto por findse puede utilizar para recuperar el valor de la clave. Si usa countentonces ato operator[]está realizando dos operaciones cuando podría haber usado solo una.
OdraEncoded

1
No necesita hacer> 0, == 1 o! = 0; esa es la comprobación exacta que C ++ hace en una declaración if (condición! = 0), por lo que puede usarif(m.count(key))
jv110

66
@ jv110 El compilador de Microsoft C ++ emite una advertencia cuando encuentra un envío de inta bool. Aunque hay otros compiladores de C ++ que no emiten una advertencia similar, prefiero usar una comparación explícita para aclarar la intención y mejorar la legibilidad. Tenga en cuenta que otros lenguajes como C # prohíben una conversión tan implícita para evitar la posibilidad de introducir errores de programación sutiles.
DavidRR

¿Cuál es la complejidad del tiempo de conteo? ¿Es solo una operación O (1)?
Mazeryt

1
@Mazeryt Dado que estamos hablando de una clase en la biblioteca estándar de C ++, ciertamente asumiría que sí. Para una discusión independiente de su pregunta, vea ¿Las tablas hash realmente pueden ser O (1)? .
DavidRR

47

C ++ 20 nos da std::map::containspara hacer eso.

#include <iostream>
#include <string>
#include <map>

int main()
{
    std::map<int, std::string> example = {{1, "One"}, {2, "Two"}, 
                                     {3, "Three"}, {42, "Don\'t Panic!!!"}};

    if(example.contains(42)) {
        std::cout << "Found\n";
    } else {
        std::cout << "Not found\n";
    }
}

34
Supongo que lo diré: finalmente.
Erik Campobadal

2
Ya era

39

Puedes usar .find():

map<string,string>::iterator i = m.find("f");

if (i == m.end()) { /* Not found */ }
else { /* Found, i->first is f, i->second is ++-- */ }

15
m.find == m.end() // not found 

Si desea utilizar otra API, busque ir a m.count(c)>0

 if (m.count("f")>0)
      cout << " is an element of m.\n";
    else 
      cout << " is not an element of m.\n";

12

Creo que quieres map::find. Si m.find("f")es igual a m.end(), entonces no se encontró la clave. De lo contrario, find devuelve un iterador que apunta al elemento encontrado.

El error se debe a que p.firstes un iterador, que no funciona para la inserción de secuencias. Cambia tu última línea a cout << (p.first)->first;. pes un par de iteradores, p.firstes un iterador, p.first->firstes la cadena clave.

Un mapa solo puede tener un elemento para una clave determinada, por equal_rangelo que no es muy útil. Está definido para el mapa, porque está definido para todos los contenedores asociativos, pero es mucho más interesante para los mapas múltiples.


En realidad, debido a que es un par de iteradores para un mapa, debería ser "cout << p.first-> first;"
stefaanv

He arreglado mi respuesta, gracias. Eso es lo que obtengo por no compilar mi código. Y tiene razón (en un comentario eliminado) sobre verificar la validez, pero solo estaba tratando de explicar por qué no pudo imprimir p.primero, y no es porque sea inválido, sabemos que se encontrará "f". Como no recomiendo usar equal_range en absoluto, no voy a mostrar un código de verificación de errores para eso.
Steve Jessop

Wow, realmente estás escaneando SO. Solo lo estaba agregando para completar, porque su punto era claro. Agregué la verificación de validez a mi respuesta anterior, pero su respuesta me superó, así que la eliminé, porque de todos modos no agregó mucho, como usted mencionó.
stefaanv

Sí, solo lo vi porque tu comentario apareció cuando publiqué el mío.
Steve Jessop

12

C++17simplificado esto un poco más con un If statement with initializer. De esta manera puedes tener tu pastel y comértelo también.

if ( auto it{ m.find( "key" ) }; it != std::end( m ) ) 
{
    // Use `structured binding` to get the key
    // and value.
    auto[ key, value ] { *it };

    // Grab either the key or value stored in the pair.
    // The key is stored in the 'first' variable and
    // the 'value' is stored in the second.
    auto mkey{ it->first };
    auto mvalue{ it->second };

    // That or just grab the entire pair pointed
    // to by the iterator.
    auto pair{ *it };
} 
else 
{
   // Key was not found..
}

4
map<string, string> m;

la clave de verificación existe o no, y el número de retorno ocurre (0/1 en el mapa):

int num = m.count("f");  
if (num>0) {    
    //found   
} else {  
    // not found  
}

la clave de verificación existe o no, y devuelve el iterador:

map<string,string>::iterator mi = m.find("f");  
if(mi != m.end()) {  
    //found  
    //do something to mi.  
} else {  
    // not found  
}  

en su pregunta, el error causado por una mala operator<<sobrecarga, porque p.firstes map<string, string>, no puede imprimirlo. prueba esto:

if(p.first != p.second) {
    cout << p.first->first << " " << p.first->second << endl;
}

1
Tienes un error tipográfico. Cambiar "cout" a "contar"
Rivka

1
Y ese error tipográfico realmente puede sorprender a alguien, ya que coutpuede significar algo muy diferente acount
modulitos

4
template <typename T, typename Key>
bool key_exists(const T& container, const Key& key)
{
    return (container.find(key) != std::end(container));
}

Por supuesto, si desea ser más elegante, siempre puede crear una función que también tome una función encontrada y una función no encontrada, algo como esto:

template <typename T, typename Key, typename FoundFunction, typename NotFoundFunction>
void find_and_execute(const T& container, const Key& key, FoundFunction found_function, NotFoundFunction not_found_function)
{
    auto& it = container.find(key);
    if (it != std::end(container))
    {
        found_function(key, it->second);
    }
    else
    {
        not_found_function(key);
    }
}

Y úsalo así:

    std::map<int, int> some_map;
    find_and_execute(some_map, 1,
        [](int key, int value){ std::cout << "key " << key << " found, value: " << value << std::endl; },
        [](int key){ std::cout << "key " << key << " not found" << std::endl; });

La desventaja de esto es que viene con un buen nombre, "find_and_execute" es incómodo y no se me ocurre nada mejor en la parte superior de mi cabeza ...


3

Tenga cuidado al comparar el resultado de búsqueda con el final, como para el mapa 'm', ya que todas las respuestas se han hecho sobre map :: iterator i = m.find ("f");

 if (i == m.end())
 {
 }
 else
 {
 }  

no debe intentar realizar ninguna operación, como imprimir la clave o el valor con el iterador i si es igual a m.end () de lo contrario, provocará un error de segmentación.


0

Comparando el código de std :: map :: find y std :: map :: count, diría que el primero puede proporcionar alguna ventaja de rendimiento:

const_iterator find(const key_type& _Keyval) const
    {   // find an element in nonmutable sequence that matches _Keyval
    const_iterator _Where = lower_bound(_Keyval); // Here one looks only for lower bound
    return (_Where == end()
        || _DEBUG_LT_PRED(this->_Getcomp(),
            _Keyval, this->_Key(_Where._Mynode()))
                ? end() : _Where);
    }

size_type count(const key_type& _Keyval) const
    {   // count all elements that match _Keyval
    _Paircc _Ans = equal_range(_Keyval); // Here both lower and upper bounds are to be found, which is presumably slower.
    size_type _Num = 0;
    _Distance(_Ans.first, _Ans.second, _Num);
    return (_Num);
    }

0

Sé que esta pregunta ya tiene algunas buenas respuestas, pero creo que vale la pena compartir mi solución.

Funciona para ambos std::mapy std::vector<std::pair<T, U>>está disponible en C ++ 11.

template <typename ForwardIterator, typename Key>
bool contains_key(ForwardIterator first, ForwardIterator last, Key const key) {
    using ValueType = typename std::iterator_traits<ForwardIterator>::value_type;

    auto search_result = std::find_if(
        first, last,
        [&key](ValueType const& item) {
            return item.first == key;
        }
    );

    if (search_result == last) {
        return false;
    } else {
        return true;
    }
}

-5

Si desea comparar un par de mapas, puede usar este método:

typedef map<double, double> TestMap;
TestMap testMap;
pair<map<double,double>::iterator,bool> controlMapValues;

controlMapValues= testMap.insert(std::pair<double,double>(x,y));
if (controlMapValues.second == false )
{
    TestMap::iterator it;
    it = testMap.find(x);

    if (it->second == y)
    {
        cout<<"Given value is already exist in Map"<<endl;
    }
}

Esta es una técnica útil.


Como principiante con la programación en C ++, tengo mucha curiosidad por qué esta respuesta es rechazada. ¿Por qué esta respuesta es impopular?
gromit190

3
@ gromit190 porque está usando otra estructura de datos para ver si la clave existe cuando std :: map ya tiene esta capacidad. Esto también requeriría la sincronización entre las dos estructuras de datos, que es una dependencia con la que nadie quiere lidiar.
Lambage

-5
map <int , char>::iterator itr;
    for(itr = MyMap.begin() ; itr!= MyMap.end() ; itr++)
    {
        if (itr->second == 'c')
        {
            cout<<itr->first<<endl;
        }
    }

3
Por favor, explique su código. Un fragmento sin ninguna explicación no suele ser útil a largo plazo.
iBug
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.