Die Idee, einen Iterator zu den Werten zu bringen, besteht darin, ihn in STL-Algorithmen zu verwenden, beispielsweise als Schnittpunkt von Schlüsseln zweier Karten. Die Lösung mit Boost erlaubt dies nicht, da ein Boost-Iterator erzeugt wird. Die schlechteste Antwort bekommt die meisten Stimmen!
Antworten:
70
Wenn Sie den Wert, den der "echte" Iterator zurückgibt, wirklich ausblenden müssen (z. B. weil Sie Ihren Schlüsseliterator mit Standardalgorithmen verwenden möchten, damit diese auf den Schlüsseln anstelle der Paare arbeiten), schauen Sie sich Boosts an transform_iterator .
[Tipp: Wenn Sie sich die Boost-Dokumentation für eine neue Klasse ansehen, lesen Sie zuerst die "Beispiele" am Ende. Sie haben dann eine sportliche Chance herauszufinden, wovon um alles in der Welt der Rest spricht :-)]
Karte ist assoziativer Container. Daher ist der Iterator ein Schlüsselpaar, val. Wenn Sie nur Schlüssel benötigen, können Sie den Werteteil des Paares ignorieren.
for(std::map<Key,Val>::iterator iter = myMap.begin(); iter != myMap.end();++iter){Key k = iter->first;//ignore value//Value v = iter->second;}
BEARBEITEN :: Wenn Sie nur die Schlüssel nach außen verfügbar machen möchten, können Sie die Karte in einen Vektor oder Schlüssel konvertieren und verfügbar machen.
Aber dann ist es wirklich eine schlechte Idee, den Iterator des Vektors draußen verfügbar zu machen.
Naveen
Setzen Sie den Iterator nicht frei.
Geben Sie
5
Vielleicht möchten Sie dies stattdessen tun: const Key& k(iter->first);
Strickli
17
Zwei Dinge, dies beantwortet die Frage des OP mit genau der Antwort, die er bereits kannte und nicht suchte. Zweitens hilft Ihnen diese Methode nicht, wenn Sie etwas tun möchten wie : std::vector<Key> v(myMap.begin(), myMap.end()).
Andreas Magnusson
Konvertieren Sie die Schlüssel nicht in einen Vektor. Das Erstellen eines neuen Vektors macht den Zweck der Iteration zunichte, die schnell sein und nichts zuweisen soll. Außerdem ist es bei großen Sets langsam.
Kevin Chen
84
Mit C ++ 11 ist die Iterationssyntax einfach. Sie iterieren immer noch über Paare, aber der Zugriff auf nur den Schlüssel ist einfach.
Leider verlangt der C ++ 17-Standard, dass Sie die valueVariable deklarieren , obwohl Sie sie nicht verwenden ( std::ignorewie man es verwenden würde, std::tie(..)funktioniert nicht, siehe diese Diskussion ).
Einige Compiler warnen Sie daher möglicherweise vor der nicht verwendeten valueVariablen! Warnungen zur Kompilierungszeit in Bezug auf nicht verwendete Variablen sind für mich kein Problem für Produktionscode. Dies gilt möglicherweise nicht für bestimmte Compilerversionen.
Könntest du es nicht grundsätzlich std :: ignore zuweisen? Würde dies tatsächlich die Effizienz des kompilierten Codes beeinträchtigen oder würde es tatsächlich zu nichts führen? (Ich meine nicht in der Bindung, sondern als Aktion innerhalb der Schleife)
KotoroShinoto
Seit C ++ 17 können Sie auch [[vielleicht_unused]] verwenden. Dies unterdrückt die Warnung. So:for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
Arhuaco
15
Unten die allgemeinere Vorlagenlösung, auf die sich Ian bezog ...
Wenn dies nicht explizit beginund enderforderlich ist, dh für eine Bereichsschleife, kann die Schleife über Schlüssel (erstes Beispiel) oder Werte (zweites Beispiel) mit erhalten werden
#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;.....}
Ja, ich weiß, das Problem ist, dass ich eine Klasse A habe {public: // Ich möchte hier einen Iterator über Schlüssel einer privaten Karte verfügbar machen. Private: map <>};
Bogdan Balan
In diesem Fall können Sie eine std :: -Liste erstellen, indem Sie std :: trasnform verwenden und nur die Schlüssel von der Karte abrufen. Anschließend können Sie den Listeniterator verfügbar machen, da durch das Einfügen weiterer Elemente in die Liste die vorhandenen Iteratoren nicht ungültig werden.
Naveen
3
Wenn Sie einen Iterator benötigen, der nur die Schlüssel zurückgibt, müssen Sie den Iterator der Karte in Ihre eigene Klasse einbinden, die die gewünschte Schnittstelle bereitstellt. Sie können wie hier eine neue Iteratorklasse von Grund auf deklarieren , um vorhandene Hilfskonstrukte zu verwenden. Diese Antwort zeigt, wie Boosts verwendet werden transform_iterator, um den Iterator in einen Iterator zu verpacken, der nur die Werte / Schlüssel zurückgibt.
Ohne Boost könnten Sie es so machen. Es wäre schön, wenn Sie anstelle von getKeyIterator () einen Cast-Operator schreiben könnten, aber ich kann ihn nicht zum Kompilieren bringen.
Ich weiß, dass dies Ihre Frage nicht beantwortet, aber eine Option, die Sie möglicherweise prüfen möchten, besteht darin, nur zwei Vektoren mit demselben Index als "verknüpfte" Informationen zu verwenden.
Wenn Sie die Anzahl der Namen nach Namen festlegen möchten, führen Sie einfach eine schnelle for-Schleife über vName.size () durch. Wenn Sie diese finden, ist dies der Index für vNameCount, den Sie suchen.
Sicher, dies gibt Ihnen möglicherweise nicht die gesamte Funktionalität der Karte, und je nachdem kann es besser sein oder auch nicht, aber es ist möglicherweise einfacher, wenn Sie die Schlüssel nicht kennen und nicht zu viel Verarbeitung hinzufügen sollten.
Denken Sie daran, wenn Sie von einem hinzufügen / löschen, müssen Sie es von dem anderen tun, sonst werden die Dinge verrückt heh: P.
Antworten:
Wenn Sie den Wert, den der "echte" Iterator zurückgibt, wirklich ausblenden müssen (z. B. weil Sie Ihren Schlüsseliterator mit Standardalgorithmen verwenden möchten, damit diese auf den Schlüsseln anstelle der Paare arbeiten), schauen Sie sich Boosts an transform_iterator .
[Tipp: Wenn Sie sich die Boost-Dokumentation für eine neue Klasse ansehen, lesen Sie zuerst die "Beispiele" am Ende. Sie haben dann eine sportliche Chance herauszufinden, wovon um alles in der Welt der Rest spricht :-)]
quelle
Karte ist assoziativer Container. Daher ist der Iterator ein Schlüsselpaar, val. Wenn Sie nur Schlüssel benötigen, können Sie den Werteteil des Paares ignorieren.
BEARBEITEN :: Wenn Sie nur die Schlüssel nach außen verfügbar machen möchten, können Sie die Karte in einen Vektor oder Schlüssel konvertieren und verfügbar machen.
quelle
const Key& k(iter->first);
std::vector<Key> v(myMap.begin(), myMap.end())
.Mit C ++ 11 ist die Iterationssyntax einfach. Sie iterieren immer noch über Paare, aber der Zugriff auf nur den Schlüssel ist einfach.
quelle
Ohne Boost
Sie können dies tun, indem Sie einfach den STL-Iterator für diese Karte erweitern. Zum Beispiel eine Zuordnung von Zeichenfolgen zu Ints:
Sie können diese Erweiterung auch in einer Vorlage ausführen , um eine allgemeinere Lösung zu erhalten.
Sie verwenden Ihren Iterator genau so, wie Sie einen Listeniterator verwenden würden, außer dass Sie über die Karten
begin()
und iterierenend()
.quelle
template<typename C> class key_iterator : public C::iterator
, etcMit C ++ 17 können Sie eine strukturierte Bindung innerhalb einer bereichsbasierten for-Schleife verwenden (indem Sie die Antwort von John H. entsprechend anpassen ):
Leider verlangt der C ++ 17-Standard, dass Sie die
value
Variable deklarieren , obwohl Sie sie nicht verwenden (std::ignore
wie man es verwenden würde,std::tie(..)
funktioniert nicht, siehe diese Diskussion ).Einige Compiler warnen Sie daher möglicherweise vor der nicht verwendeten
value
Variablen! Warnungen zur Kompilierungszeit in Bezug auf nicht verwendete Variablen sind für mich kein Problem für Produktionscode. Dies gilt möglicherweise nicht für bestimmte Compilerversionen.quelle
for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
Unten die allgemeinere Vorlagenlösung, auf die sich Ian bezog ...
Alle Credits gehen an Ian ... Danke Ian.
quelle
Sie suchen nach map_keys , mit denen Sie Dinge wie schreiben können
quelle
BOOST_FOREACH(const key_t& key, ...
Hier ist ein Beispiel, wie dies mit dem transform_iterator von Boost gemacht wird
quelle
Wenn dies nicht explizit
begin
undend
erforderlich ist, dh für eine Bereichsschleife, kann die Schleife über Schlüssel (erstes Beispiel) oder Werte (zweites Beispiel) mit erhalten werdenquelle
Du willst das machen?
quelle
Wenn Sie einen Iterator benötigen, der nur die Schlüssel zurückgibt, müssen Sie den Iterator der Karte in Ihre eigene Klasse einbinden, die die gewünschte Schnittstelle bereitstellt. Sie können wie hier eine neue Iteratorklasse von Grund auf deklarieren , um vorhandene Hilfskonstrukte zu verwenden. Diese Antwort zeigt, wie Boosts verwendet werden
transform_iterator
, um den Iterator in einen Iterator zu verpacken, der nur die Werte / Schlüssel zurückgibt.quelle
Du könntest
std::map<K,V>::iterator
std::transform
Ihresmap.begin()
zumap.end()
mit einemboost::bind( &pair::second, _1 )
Funktor->second
Mitglied, während Sie mit einerfor
Schleife iterieren .quelle
Diese Antwort ist wie die von Rodrigob, außer ohne die
BOOST_FOREACH
. Sie können stattdessen den Bereich von c ++ verwenden, der auf basiert.quelle
Ohne Boost könnten Sie es so machen. Es wäre schön, wenn Sie anstelle von getKeyIterator () einen Cast-Operator schreiben könnten, aber ich kann ihn nicht zum Kompilieren bringen.
quelle
Für die Nachwelt und da ich versucht habe, einen Weg zum Erstellen eines Bereichs zu finden, besteht eine Alternative darin, boost :: adapters :: transform zu verwenden
Hier ist ein kleines Beispiel:
Wenn Sie die Werte durchlaufen möchten, verwenden Sie sie
t.second
im Lambda.quelle
Hier finden Sie viele gute Antworten. Im Folgenden finden Sie einige Ansätze, mit denen Sie Folgendes schreiben können:
Wenn Sie das schon immer wollten, dann ist hier der Code für MapKeys ():
quelle
Ich habe Ians Antwort übernommen, um mit allen Kartentypen zu arbeiten, und die Rückgabe einer Referenz für behoben
operator*
quelle
Ich weiß, dass dies Ihre Frage nicht beantwortet, aber eine Option, die Sie möglicherweise prüfen möchten, besteht darin, nur zwei Vektoren mit demselben Index als "verknüpfte" Informationen zu verwenden.
Also in ..
Wenn Sie die Anzahl der Namen nach Namen festlegen möchten, führen Sie einfach eine schnelle for-Schleife über vName.size () durch. Wenn Sie diese finden, ist dies der Index für vNameCount, den Sie suchen.
Sicher, dies gibt Ihnen möglicherweise nicht die gesamte Funktionalität der Karte, und je nachdem kann es besser sein oder auch nicht, aber es ist möglicherweise einfacher, wenn Sie die Schlüssel nicht kennen und nicht zu viel Verarbeitung hinzufügen sollten.
Denken Sie daran, wenn Sie von einem hinzufügen / löschen, müssen Sie es von dem anderen tun, sonst werden die Dinge verrückt heh: P.
quelle