Gewusst wie: abrufen aller Schlüssel (oder Werten) aus einer std::map und legen Sie Sie in einen Vektor?

StackOverflow https://stackoverflow.com/questions/110157

  •  02-07-2019
  •  | 
  •  

Frage

Dies ist eine der Möglichkeiten, ich komme aus:

struct RetrieveKey
{
    template <typename T>
    typename T::first_type operator()(T keyValuePair) const
    {
        return keyValuePair.first;
    }
};

map<int, int> m;
vector<int> keys;

// Retrieve all keys
transform(m.begin(), m.end(), back_inserter(keys), RetrieveKey());

// Dump all keys
copy(keys.begin(), keys.end(), ostream_iterator<int>(cout, "\n"));

Natürlich, wir können auch wieder alle Werte aus der Karte, indem Sie definieren ein weiterer Funktor RetrieveValues.

Gibt es eine andere Möglichkeit, dies zu erreichen einfach?(Ich bin immer gefragt, warum std::map nicht enthalten eine member-Funktion für uns zu tun.)

War es hilfreich?

Lösung

Während Ihre Lösung sollte funktionieren, es kann schwierig sein, zu Lesen, je nach skill-level von deinen Kollegen-Programmierer.Zusätzlich, bewegt es sich Funktionalität entfernt von der Ruf Website.Die Wartung ein wenig schwieriger.

Ich bin mir nicht sicher, ob es Ihr Ziel ist, die Schlüssel in einen Vektor oder ausdrucken zu cout, also mache ich beides.Sie können versuchen, so etwas wie dieses:

map<int, int> m;
vector<int> v;
for(map<int,int>::iterator it = m.begin(); it != m.end(); ++it) {
  v.push_back(it->first);
  cout << it->first << "\n";
}

Oder noch einfacher, wenn Sie mit Boost:

map<int,int> m;
pair<int,int> me; // what a map<int, int> is made of
vector<int> v;
BOOST_FOREACH(me, m) {
  v.push_back(me.first);
  cout << me.first << "\n";
}

Persönlich mag ich die BOOST_FOREACH version, weil es ist weniger Tippen und es wird sehr explizit darüber, was es tut.

Andere Tipps

//c++0x too
std::map<int,int> mapints;
std::vector<int> vints;
vints.reserve(mapints.size());
for(auto const& imap: mapints)
    vints.push_back(imap.first);

Es ist ein boost-Bereich-Adapter für diesen Zweck:

vector<int> keys;
// Retrieve all keys
boost::copy(m | boost::adaptors::map_keys, std::back_inserter(keys));

Es ist eine ähnliche map_values Spektrum-Adapter für die Extraktion der Werte.

C++0x hat uns eine weitere, sehr gute Lösung:

std::vector<int> keys;

std::transform(
    m_Inputs.begin(),
    m_Inputs.end(),
    std::back_inserter(keys),
    [](const std::map<int,int>::value_type &pair){return pair.first;});

@DanDan Antwort, die mit C++11 ist:

using namespace std;
vector<int> keys;

transform(begin(map_in), end(map_in), back_inserter(keys), 
            [](decltype(map_in)::value_type const& pair) {
    return pair.first;
}); 

und mit C++14 (wie erwähnt von @ivan.ukr) wir ersetzen können decltype(map_in)::value_type mit auto.

Der SGI STL hat eine Erweiterung namens select1st.Schade, dass es nicht in der standard-STL!

Ich denke, die BOOST_FOREACH oben dargestellt ist schön und sauber, allerdings gibt es eine weitere option mit BOOST als gut.

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

std::map<int, int> m;
std::vector<int> keys;

using namespace boost::lambda;

transform(      m.begin(), 
                m.end(), 
                back_inserter(keys), 
                bind( &std::map<int,int>::value_type::first, _1 ) 
          );

copy( keys.begin(), keys.end(), std::ostream_iterator<int>(std::cout, "\n") );

Persönlich, ich don ' T denke, dieser Ansatz ist so sauber wie die BOOST_FOREACH Ansatz in diesem Fall, aber boost::lambda-kann wirklich sauber in den anderen Fällen.

Ihre Lösung ist gut, aber Sie können verwenden Sie einen iterator, um es zu tun:

std::map<int, int> m;
m.insert(std::pair<int, int>(3, 4));
m.insert(std::pair<int, int>(5, 6));
for(std::map<int, int>::const_iterator it = m.begin(); it != m.end(); it++)
{
    int key = it->first;
    int value = it->second;
    //Do something
}

Auch, wenn Sie Boost verwenden transform_iterator um zu vermeiden, dass eine temporäre Kopie des keys.

Sie können die vielseitige boost::transform_iterator.Die transform_iterator können Sie verwandeln die iterierten Werte, zum Beispiel in unserem Fall, wenn Sie wollen, um sich nur mit dem Schlüssel, nicht die Werte.Finden http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/transform_iterator.html#example

Bisschen c++11 nehmen:

std::map<uint32_t, uint32_t> items;
std::vector<uint32_t> itemKeys;
for (auto & kvp : items)
{
    itemKeys.emplace_back(kvp.first);
    std::cout << kvp.first << std::endl;
}

Die besten nicht-sgi non-boost, STL-Lösung zu erweitern, map::iterator wie so:

template<class map_type>
class key_iterator : public map_type::iterator
{
public:
    typedef typename map_type::iterator map_iterator;
    typedef typename map_iterator::value_type::first_type key_type;

    key_iterator(const map_iterator& other) : map_type::iterator(other) {} ;

    key_type& operator *()
    {
        return map_type::iterator::operator*().first;
    }
};

// helpers to create iterators easier:
template<class map_type>
key_iterator<map_type> key_begin(map_type& m)
{
    return key_iterator<map_type>(m.begin());
}
template<class map_type>
key_iterator<map_type> key_end(map_type& m)
{
    return key_iterator<map_type>(m.end());
}

und dann verwenden Sie wie so:

        map<string,int> test;
        test["one"] = 1;
        test["two"] = 2;

        vector<string> keys;

//      // method one
//      key_iterator<map<string,int> > kb(test.begin());
//      key_iterator<map<string,int> > ke(test.end());
//      keys.insert(keys.begin(), kb, ke);

//      // method two
//      keys.insert(keys.begin(),
//           key_iterator<map<string,int> >(test.begin()),
//           key_iterator<map<string,int> >(test.end()));

        // method three (with helpers)
        keys.insert(keys.begin(), key_begin(test), key_end(test));

        string one = keys[0];

Hier ist eine nette Funktion-Vorlage mit C++11 Magie, arbeitet für sowohl std::map, std::unordered_map:

template<template <typename...> class MAP, class KEY, class VALUE>
std::vector<KEY>
keys(const MAP<KEY, VALUE>& map)
{
    std::vector<KEY> result;
    result.reserve(map.size());
    for(const auto& it : map){
        result.emplace_back(it.first);
    }
    return result;
}

Überprüfen Sie es heraus hier: http://ideone.com/lYBzpL

Ähnlich einem der Beispiele hier vereinfacht std::map Verwendung Perspektive.

template<class KEY, class VALUE>
std::vector<KEY> getKeys(const std::map<KEY, VALUE>& map)
{
    std::vector<KEY> keys(map.size());
    for (const auto& it : map)
        keys.push_back(it.first);
    return keys;
}

Wie diese:

auto keys = getKeys(yourMap);

Basierend auf dem @rusty-parks Lösung, aber in c++17:

std::map<uint32_t, uint32_t> items;
std::vector<uint32_t> itemKeys;
for (auto const& [key, std:ignore] : items) {
  itemKeys.emplace_back(key);
}

(Ich bin immer gefragt, warum std::map nicht enthalten eine member-Funktion für uns zu tun.)

Denn es können nicht tun es besser als Sie es tun können.Wenn eine Methode ist die Implementierung wird kein überlegen, eine Kostenlose Funktion, die Umsetzung dann in der Regel sollten Sie nicht schreiben Sie eine Methode;Sie sollten schreiben, eine Kostenlose Funktion.

Es ist auch nicht sofort klar, warum es sinnvoll ist, sowieso.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top