La idea de obtener un iterador para los valores es usarlo en algoritmos STL, por ejemplo, la intersección de claves de dos mapas. La solución que involucra Boost no permite esto, porque producirá un iterador Boost. ¡La peor respuesta obtiene la mayoría de los votos!
Respuestas:
70
Si realmente necesita ocultar el valor que devuelve el iterador "real" (por ejemplo, porque desea utilizar su iterador de clave con algoritmos estándar, para que operen en las claves en lugar de los pares), eche un vistazo a Boost transform_iterator .
[Consejo: cuando mire la documentación de Boost para una nueva clase, lea primero los "ejemplos" al final. Entonces tienes una oportunidad deportiva de descubrir de qué demonios está hablando el resto :-)]
El mapa es un contenedor asociativo. Por lo tanto, el iterador es un par de claves, val. SI solo necesita claves, puede ignorar la parte del valor del par.
for(std::map<Key,Val>::iterator iter = myMap.begin(); iter != myMap.end();++iter){Key k = iter->first;//ignore value//Value v = iter->second;}
EDITAR: en caso de que desee exponer solo las teclas al exterior, puede convertir el mapa a vector o teclas y exponer.
Pero entonces será una muy mala idea exponer el iterador del vector afuera.
Naveen
No exponga el iterador. Solo proporcione las claves en el vector
aJ.
55
Es posible que desee hacer esto en su lugar: const Key& k(iter->first);
strickli
17
Dos cosas, esto responde a la pregunta de la OP con exactamente la respuesta que ya sabía y no estaba buscando, en segundo lugar, este método no le ayudará si desea hacer algo como: std::vector<Key> v(myMap.begin(), myMap.end()).
Andreas Magnusson el
No conviertas las claves en un vector. Hacer un nuevo vector anula el propósito de la iteración, que se supone que es rápida y no asigna nada. Además, será lento para conjuntos grandes.
Kevin Chen
85
Con C ++ 11, la sintaxis de iteración es simple. Todavía itera sobre pares, pero acceder solo a la clave es fácil.
Desafortunadamente, el estándar C ++ 17 requiere que declare la valuevariable, aunque no la esté usando ( std::ignorecomo se usaría para std::tie(..)no funciona, vea esta discusión ).
¡Por lo tanto, algunos compiladores pueden advertirle sobre la valuevariable no utilizada ! Las advertencias en tiempo de compilación con respecto a las variables no utilizadas son una prohibición para cualquier código de producción en mi mente. Por lo tanto, esto puede no ser aplicable para ciertas versiones del compilador.
¿no podrías asignarlo a std :: ignore en principio? ¿Eso realmente perjudicaría la eficiencia en el código compilado o realmente no se evaluaría? (No me refiero a la encuadernación, sino más bien como una acción dentro del bucle)
KotoroShinoto
Desde C ++ 17 también puedes usar [[maybe_unused]]. Esto suprime la advertencia. Así:for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
arhuaco
15
Debajo de la solución más general a la que se refirió Ian ...
Cuando no es explícito beginy endes necesario, es decir, para el bucle de rango, el bucle sobre las teclas (primer ejemplo) o los valores (segundo ejemplo) se pueden obtener con
#include<boost/range/adaptors.hpp>
map<Key,Value> m;for(auto k : boost::adaptors::keys(m))
cout << k << endl;for(auto v : boost::adaptors::values(m))
cout << v << endl;
std::map<type,type>::iterator iter = myMap.begin();
std::map<type,type>::iterator iter = myMap.end();for(; iter != endIter;++iter){
type key = iter->first;.....}
Sí, lo sé, el problema es que tengo una clase A {public: // me gustaría exponer un iterador sobre las teclas del mapa privado aquí privado: mapa <>};
Bogdan Balan
En ese caso, creo que puede crear una lista std :: usando std :: trasnform y recogiendo solo las claves del mapa. Luego puede exponer el iterador de la lista ya que insertar más elementos en la lista no invalidará los iteradores existentes.
Naveen
3
Si necesita un iterador que solo devuelva las claves, debe ajustar el iterador del mapa en su propia clase que proporcione la interfaz deseada. Puede declarar una nueva clase de iterador desde cero como aquí , para usar construcciones auxiliares existentes. Esta respuesta muestra cómo usar Boost transform_iteratorpara ajustar el iterador en uno que solo devuelve los valores / claves.
Sin Boost, podrías hacerlo así. Sería bueno si pudiera escribir un operador de conversión en lugar de getKeyIterator (), pero no puedo hacer que se compile.
Sé que esto no responde a su pregunta, pero una opción que puede considerar es simplemente tener dos vectores con el mismo índice como información "vinculada".
si desea el recuento de nombres por nombre, simplemente haga su bucle rápido for vName.size (), y cuando lo encuentre, ese es el índice de vNameCount que está buscando.
Claro que esto puede no darle toda la funcionalidad del mapa, y dependiendo puede o no ser mejor, pero podría ser más fácil si no conoce las claves y no debería agregar demasiado procesamiento.
Solo recuerde que cuando agregue / elimine uno, debe hacerlo desde el otro o las cosas se volverán locas je: P
Respuestas:
Si realmente necesita ocultar el valor que devuelve el iterador "real" (por ejemplo, porque desea utilizar su iterador de clave con algoritmos estándar, para que operen en las claves en lugar de los pares), eche un vistazo a Boost transform_iterator .
[Consejo: cuando mire la documentación de Boost para una nueva clase, lea primero los "ejemplos" al final. Entonces tienes una oportunidad deportiva de descubrir de qué demonios está hablando el resto :-)]
fuente
El mapa es un contenedor asociativo. Por lo tanto, el iterador es un par de claves, val. SI solo necesita claves, puede ignorar la parte del valor del par.
EDITAR: en caso de que desee exponer solo las teclas al exterior, puede convertir el mapa a vector o teclas y exponer.
fuente
const Key& k(iter->first);
std::vector<Key> v(myMap.begin(), myMap.end())
.Con C ++ 11, la sintaxis de iteración es simple. Todavía itera sobre pares, pero acceder solo a la clave es fácil.
fuente
Sin refuerzo
Puede hacerlo simplemente extendiendo el iterador STL para ese mapa. Por ejemplo, una asignación de cadenas a ints:
También puede realizar esta extensión en una plantilla , para una solución más general.
Utiliza su iterador exactamente como lo haría con un iterador de lista, excepto que está iterando sobre el mapa
begin()
yend()
.fuente
template<typename C> class key_iterator : public C::iterator
, etc.Con C ++ 17 puede usar un enlace estructurado dentro de un bucle for basado en rango (adaptando la respuesta de John H. en consecuencia):
Desafortunadamente, el estándar C ++ 17 requiere que declare la
value
variable, aunque no la esté usando (std::ignore
como se usaría parastd::tie(..)
no funciona, vea esta discusión ).¡Por lo tanto, algunos compiladores pueden advertirle sobre la
value
variable no utilizada ! Las advertencias en tiempo de compilación con respecto a las variables no utilizadas son una prohibición para cualquier código de producción en mi mente. Por lo tanto, esto puede no ser aplicable para ciertas versiones del compilador.fuente
for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
Debajo de la solución más general a la que se refirió Ian ...
Todos los créditos van a Ian ... Gracias Ian.
fuente
Estás buscando map_keys , con él puedes escribir cosas como
fuente
BOOST_FOREACH(const key_t& key, ...
Aquí hay un ejemplo de cómo hacerlo usando el transform_iterator de Boost
fuente
Cuando no es explícito
begin
yend
es necesario, es decir, para el bucle de rango, el bucle sobre las teclas (primer ejemplo) o los valores (segundo ejemplo) se pueden obtener confuente
Quieres hacer esto?
fuente
Si necesita un iterador que solo devuelva las claves, debe ajustar el iterador del mapa en su propia clase que proporcione la interfaz deseada. Puede declarar una nueva clase de iterador desde cero como aquí , para usar construcciones auxiliares existentes. Esta respuesta muestra cómo usar Boost
transform_iterator
para ajustar el iterador en uno que solo devuelve los valores / claves.fuente
Tú podrías
std::map<K,V>::iterator
std::transform
de tumap.begin()
tomap.end()
con unboost::bind( &pair::second, _1 )
functor->second
miembro mientras itera con unfor
bucle.fuente
Esta respuesta es como la de rodrigob, excepto sin el
BOOST_FOREACH
. Puede usar el rango de c ++ basado en su lugar.fuente
Sin Boost, podrías hacerlo así. Sería bueno si pudiera escribir un operador de conversión en lugar de getKeyIterator (), pero no puedo hacer que se compile.
fuente
Para la posteridad, y dado que estaba tratando de encontrar una manera de crear un rango, una alternativa es usar boost :: adapters :: transform
Aquí hay un pequeño ejemplo:
Si desea iterar sobre los valores, utilícelo
t.second
en lambda.fuente
Muchas buenas respuestas aquí, a continuación hay un enfoque que utiliza un par de ellas que le permite escribir esto:
Si eso es lo que siempre quiso, entonces aquí está el código para MapKeys ():
fuente
Adopté la respuesta de Ian para trabajar con todos los tipos de mapas y arreglé la devolución de una referencia para
operator*
fuente
Sé que esto no responde a su pregunta, pero una opción que puede considerar es simplemente tener dos vectores con el mismo índice como información "vinculada".
Entonces en ...
si desea el recuento de nombres por nombre, simplemente haga su bucle rápido for vName.size (), y cuando lo encuentre, ese es el índice de vNameCount que está buscando.
Claro que esto puede no darle toda la funcionalidad del mapa, y dependiendo puede o no ser mejor, pero podría ser más fácil si no conoce las claves y no debería agregar demasiado procesamiento.
Solo recuerde que cuando agregue / elimine uno, debe hacerlo desde el otro o las cosas se volverán locas je: P
fuente