A idéia de obter um iterador para os valores é usá-lo nos algoritmos STL, por exemplo, interseção de chaves de dois mapas. A solução que envolve o Boost não permite isso, porque produzirá um iterador do Boost. A pior resposta recebe mais votos!
Respostas:
70
Se você realmente precisa ocultar o valor que o iterador "real" retorna (por exemplo, porque deseja usar seu iterador de chaves com algoritmos padrão, para que eles operem nas chaves em vez dos pares), consulte o Boost. transform_iterator .
[Dica: ao consultar a documentação do Boost para uma nova classe, leia os "exemplos" no final primeiro. Você tem uma chance esportiva de descobrir o que está falando sobre o resto :-)]
Mas será uma péssima idéia expor o iterador do vetor fora.
Naveen
Não exponha o iterador. Basta fornecer as chaves no vetor
aJ.
5
Você pode querer fazer isso em vez disso: const Key& k(iter->first);
strickli
17
Duas coisas, isso responde a pergunta do OP com exatamente a resposta que ele já sabia e não estava procurando, em segundo lugar, este método não irá ajudá-lo se você quiser fazer algo como: std::vector<Key> v(myMap.begin(), myMap.end()).
Andreas Magnusson
Não converta as chaves em um vetor. Criar um novo vetor anula o propósito da iteração, que deveria ser rápida e não alocar nada. Além disso, será lento para conjuntos grandes.
Kevin Chen
85
Com o C ++ 11, a sintaxe da iteração é simples. Você ainda interage com pares, mas é fácil acessar apenas a chave.
Infelizmente, o padrão C ++ 17 exige que você declare a valuevariável, mesmo que você não a esteja usando ( std::ignorecomo se usaria para std::tie(..)não funcionar, consulte esta discussão ).
Alguns compiladores podem avisá-lo sobre a valuevariável não utilizada ! Avisos em tempo de compilação sobre variáveis não utilizadas não são aplicáveis a nenhum código de produção em minha mente. Portanto, isso pode não ser aplicável a determinadas versões do compilador.
você não poderia atribuí-lo a std :: ignore em princípio? Isso realmente prejudicaria a eficiência no código compilado ou seria realmente avaliado para nada? (I não significam na ligao, mas sim como uma acção dentro do ciclo)
KotoroShinoto
Desde o C ++ 17, você também pode usar [[maybe_unused]]. Isso suprime o aviso. Assim:for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
arhuaco
15
Abaixo da solução de modelo mais geral à qual Ian se referiu ...
Quando não é explícito begine endé necessário, ou seja, para loop de intervalo, as chaves de loop over (primeiro exemplo) ou valores (segundo exemplo) podem ser obtidas com
#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;.....}
Sim, eu sei, o problema é que tenho uma classe A {public: // gostaria de expor um iterador sobre as chaves do mapa privado aqui private: map <>};
Bogdan Balan
Nesse caso, acho que você pode criar uma lista std :: usando std :: trasnform e escolhendo apenas as chaves do mapa. Em seguida, você pode expor o iterador da lista, pois a inserção de mais elementos na lista não invalidará os iteradores existentes.
Naveen
3
Se você precisar de um iterador que apenas retorne as chaves, precisará agrupar o iterador do mapa em sua própria classe que forneça a interface desejada. Você pode declarar uma nova classe de iterador do zero, como aqui , de usar construções auxiliares existentes. Esta resposta mostra como usar os Boost's transform_iteratorpara agrupar o iterador em um que retorne apenas os valores / chaves.
Sem o Boost, você poderia fazer assim. Seria bom se você pudesse escrever um operador de conversão em vez de getKeyIterator (), mas não consigo compilar.
Sei que isso não responde à sua pergunta, mas uma opção que você pode querer considerar é ter apenas dois vetores com o mesmo índice sendo informações "vinculadas".
se você quiser a contagem de nomes por nome, faça seu loop for for rápido em vName.size () e, quando descobrir, esse é o índice do vNameCount que você está procurando.
Certamente, isso pode não lhe proporcionar toda a funcionalidade do mapa, e dependendo pode ou não ser melhor, mas pode ser mais fácil se você não souber as chaves e não adicionar muito processamento.
Lembre-se de que quando você adiciona / exclui de um, deve fazê-lo do outro ou as coisas ficam loucas heh: P
Respostas:
Se você realmente precisa ocultar o valor que o iterador "real" retorna (por exemplo, porque deseja usar seu iterador de chaves com algoritmos padrão, para que eles operem nas chaves em vez dos pares), consulte o Boost. transform_iterator .
[Dica: ao consultar a documentação do Boost para uma nova classe, leia os "exemplos" no final primeiro. Você tem uma chance esportiva de descobrir o que está falando sobre o resto :-)]
fonte
mapa é contêiner associativo. Portanto, o iterador é um par de chaves, val. Se você precisar apenas de chaves, poderá ignorar a parte do valor do par.
EDIT:: Caso deseje expor apenas as chaves para fora, é possível converter o mapa em vetor ou chaves e expor.
fonte
const Key& k(iter->first);
std::vector<Key> v(myMap.begin(), myMap.end())
.Com o C ++ 11, a sintaxe da iteração é simples. Você ainda interage com pares, mas é fácil acessar apenas a chave.
fonte
Sem impulso
Você pode fazer isso simplesmente estendendo o iterador STL para esse mapa. Por exemplo, um mapeamento de strings para ints:
Você também pode executar esta extensão em um modelo , para uma solução mais geral.
Você usa seu iterador exatamente como usaria um iterador de lista, exceto que está iterando sobre o mapa
begin()
eend()
.fonte
template<typename C> class key_iterator : public C::iterator
, etcCom o C ++ 17, você pode usar uma ligação estruturada dentro de um loop for baseado em intervalo (adaptando a resposta de John H. de acordo):
Infelizmente, o padrão C ++ 17 exige que você declare a
value
variável, mesmo que você não a esteja usando (std::ignore
como se usaria parastd::tie(..)
não funcionar, consulte esta discussão ).Alguns compiladores podem avisá-lo sobre a
value
variável não utilizada ! Avisos em tempo de compilação sobre variáveis não utilizadas não são aplicáveis a nenhum código de produção em minha mente. Portanto, isso pode não ser aplicável a determinadas versões do compilador.fonte
for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
Abaixo da solução de modelo mais geral à qual Ian se referiu ...
Todos os créditos vão para Ian ... Obrigado Ian.
fonte
Você está procurando map_keys , com ele você pode escrever coisas como
fonte
BOOST_FOREACH(const key_t& key, ...
Aqui está um exemplo de como fazer isso usando o transform_iterator do Boost
fonte
Quando não é explícito
begin
eend
é necessário, ou seja, para loop de intervalo, as chaves de loop over (primeiro exemplo) ou valores (segundo exemplo) podem ser obtidas comfonte
Você quer fazer isso?
fonte
Se você precisar de um iterador que apenas retorne as chaves, precisará agrupar o iterador do mapa em sua própria classe que forneça a interface desejada. Você pode declarar uma nova classe de iterador do zero, como aqui , de usar construções auxiliares existentes. Esta resposta mostra como usar os Boost's
transform_iterator
para agrupar o iterador em um que retorne apenas os valores / chaves.fonte
Você poderia
std::map<K,V>::iterator
std::transform
do seumap.begin()
paramap.end()
com umboost::bind( &pair::second, _1 )
functor->second
membro enquanto itera com umfor
loop.fonte
Esta resposta é como rodrigob, exceto sem o
BOOST_FOREACH
. Você pode usar o intervalo do c ++ com base em.fonte
Sem o Boost, você poderia fazer assim. Seria bom se você pudesse escrever um operador de conversão em vez de getKeyIterator (), mas não consigo compilar.
fonte
Para a posteridade, e como eu estava tentando encontrar uma maneira de criar um intervalo, uma alternativa é usar o boost :: adapters :: transform
Aqui está um pequeno exemplo:
Se você deseja iterar sobre os valores, use
t.second
no lambda.fonte
Muitas respostas boas aqui, abaixo, são uma abordagem usando algumas delas, que permitem escrever isso:
Se é isso que você sempre quis, aqui está o código para MapKeys ():
fonte
Adotei a resposta de Ian para trabalhar com todos os tipos de mapa e corrigi o retorno de uma referência para
operator*
fonte
Sei que isso não responde à sua pergunta, mas uma opção que você pode querer considerar é ter apenas dois vetores com o mesmo índice sendo informações "vinculadas".
Então em ..
se você quiser a contagem de nomes por nome, faça seu loop for for rápido em vName.size () e, quando descobrir, esse é o índice do vNameCount que você está procurando.
Certamente, isso pode não lhe proporcionar toda a funcionalidade do mapa, e dependendo pode ou não ser melhor, mas pode ser mais fácil se você não souber as chaves e não adicionar muito processamento.
Lembre-se de que quando você adiciona / exclui de um, deve fazê-lo do outro ou as coisas ficam loucas heh: P
fonte