std :: map에서 모든 키 (또는 값)를 검색하여 벡터에 넣는 방법은 무엇입니까?


246

이것은 내가 나오는 가능한 방법 중 하나입니다.

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"));

물론 다른 functor RetrieveValues 를 정의하여 맵에서 모든 값을 검색 할 수도 있습니다 .

이것을 쉽게 달성 할 수있는 다른 방법이 있습니까? (왜 std :: map에 멤버 함수가 포함되어 있지 않은지 항상 궁금합니다.)


10
귀하의 솔루션이 최고입니다 ...
linello

4
내가 이것을 추가 할 유일한 생각은 keys.reserve(m.size());입니다.
Galik

답변:


176

솔루션이 작동해야하지만 동료 프로그래머의 기술 수준에 따라 읽기 어려울 수 있습니다. 또한 기능을 호출 사이트에서 멀리 이동시킵니다. 유지 관리를 좀 더 어렵게 만들 수 있습니다.

당신의 목표가 키를 벡터로 가져 오거나 cout으로 인쇄하여 두 가지를 모두 수행하는 것이 확실하지 않습니다. 다음과 같이 시도해보십시오.

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";
}

또는 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";
}

개인적으로 BOOST_FOREACH 버전은 타이핑이 적고 수행중인 작업에 대해 매우 명확하기 때문에 좋아합니다.


1
Google 검색 후 여기로 돌아간 수치로 이동하십시오. 너의 대답은 내가 :) 선호
mpen

4
@Jere-실제로 작업 했습니까 BOOST_FOREACH? 여기에서 제안하는 코드는 완전히 잘못되었습니다
Manuel

2
@Jamie-다른 방법이지만 부스트 문서는 유형에 쉼표가 포함되어 있으면 BOOST_FOREACH 이전에 변수 및 유형을 지정하는 것을 보여줍니다. 또한 typedefing을 보여줍니다. 그래서 혼란 스럽습니다. 코드에 어떤 문제가 있습니까?
Jere.Jones

17
궁금한 점은 크기 조정 할당을 방지하기 위해 벡터의 크기를 미리 조정하는 것이 타당하지 않습니까?
Alan

2
이렇게 잊지 마세요 v.reserve(m.size())전송시 벡터 크기 조정을 피하기 위해.
브라이언 화이트

157
//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);

4
좋은. 에 대해 잊어 버리십시오 it = ...begin(); it != ...end. 물론 가장 좋은 방법은 std :: map이 벡터를 반환하는 메소드 keys ()를 갖는 것입니다.
masterxilo

2
@ BenHymers : C ++ 11이 C ++가 된 answered Mar 13 '12 at 22:33 몇 개월 이 지나서이 답변이 나에게 주어진 것 같습니다 .
Sebastian Mach

37
@ BenHymers 그러나 그것은 지금 질문을 읽는 사람에게 유용합니다. 이것은 모든 것을 요구하는 것입니다-asker를 도울뿐만 아니라 다른 모든 사람들.
Luchian Grigore

9
복사 작업이 없으므로 (자동 & imap)이 더 정확합니다.
HelloWorld

2
@StudentT, 더 나은 아직 for(auto const & imap : mapints).
cp.engr

61

부스트 범위 어댑터 이 목적은 :

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

값을 추출하기위한 비슷한 map_values ​​범위 어댑터가 있습니다.


1
불행히도 boost::adaptorsBoost 1.43까지는 사용할 수없는 것 같습니다 . 데비안 (스퀴즈)의 현재 안정적인 릴리스는 이벤트 1.42 부스트
미카엘 르 Baillif

2
그 유감. Boost 1.42는 2010 년 2 월에 출시되었습니다.
Alastair

이 시점에서 Squeeze Updates 또는 백 포트 저장소가 Boost 1.44를 제공해서는 안됩니까?
Luis Machuca

어떤 부스트 헤더가 정의되어 있습니까?
James Wierzba

1
다음에 정의 된 링크 된 도코를 참조하십시오.boost/range/adaptor/map.hpp
Alastair

46

C ++ 0x는 우리에게 더욱 훌륭한 솔루션을 제공했습니다.

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;});

22
내 견해로는 그것에 대해 훌륭한 것이 없습니다. std :: vector <int> 키; keys.reserve (m_Inputs.size ()); for (auto keyValue : m_Inputs) {keys.push_back (keyValue.first); } 암호 변환보다 훨씬 낫다. 성능면에서도 마찬가지입니다. 이것은 더 낫다.
Jagannath

5
비슷한 성능을 원한다면 여기에서 키 크기를 예약 할 수 있습니다. for 루프를 피하려면 변환을 사용하십시오.
DanDan

4
그냥 추가하고 싶습니다-[] (const auto & pair)를 사용할 수 있습니다
ivan.ukr

@ ivan.ukr 어떤 컴파일러를 사용하고 있습니까? 다음 구문은 허용되지 않습니다 : 'const auto &': 매개 변수는 'auto'를 포함하는 유형을 가질 수 없습니다
Gobe

4
@ 람다에서 ivan.ukr 자동 매개 변수는 C ++ 14입니다
roalz

16

C ++ 11을 사용하는 @ DanDan의 대답은 다음과 같습니다.

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;
}); 

사용 및 C (@ ivan.ukr으로 명시된) 14 ++ 우리는 바꿀 수 decltype(map_in)::value_typeauto.


5
keys.reserve(map_in.size());효율성을 높이기 위해 추가 할 수 있습니다 .
Galik

변환 방법이 실제로 for-loop보다 더 많은 코드를 사용한다는 것을 알았습니다.
user1633272

const는 유형 뒤에 넣을 수 있습니다! 거의 잊어 버렸습니다.
Zhang


10

귀하의 솔루션은 훌륭하지만 반복기를 사용하여 수행 할 수 있습니다.

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
}

10

@ rusty-parks 솔루션을 기반으로하지만 C ++ 17로

std :: map <int, int> 항목;
std :: vector <int> itemKeys;

for (const auto & [key, ignore] : 항목)
{
    itemKeys.push_back (키);
}

나는 std::ignoreca가 이런 식으로 구조적 바인딩에 사용 되지 않는다고 생각 합니다. 컴파일 오류가 발생했습니다. ignored단순히 사용되지 않는 정규 변수를 사용하는 것으로 충분합니다 .
jb

1
@jb 감사합니다. 실제로, 구조적 바인딩과 함께 std::ignore사용하도록 의도 된 std::tie것은 아닙니다. 코드를 업데이트했습니다.
Madiyar

9

위에서 제시 한 BOOST_FOREACH는 훌륭하고 깨끗하지만 BOOST를 사용하는 또 다른 옵션이 있습니다.

#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") );

개인적 으로이 방법은 BOOST_FOREACH 방법만큼 깨끗하지 않다고 생각하지만 boost :: lambda는 다른 경우에는 실제로 깨끗할 수 있습니다.



7

C ++ 11의 비트는 다음과 같습니다.

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;
}


5

다음은 C ++ 11 매직을 사용하는 멋진 함수 템플릿입니다. 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;
}

여기에서 확인하십시오 : http://ideone.com/lYBzpL


4

sgi가 아닌 non-boost STL 솔루션은 map :: iterator를 다음과 같이 확장하는 것입니다.

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());
}

그런 다음 다음과 같이 사용하십시오.

        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];

1
const_iterator를 만들고 필요에 따라 반복자를 반복하기 위해 독자에게 맡길 것입니다.
마리우스

-1

원자지도 예제

#include <iostream>
#include <map>
#include <vector> 
#include <atomic>

using namespace std;

typedef std::atomic<std::uint32_t> atomic_uint32_t;
typedef std::map<int, atomic_uint32_t> atomic_map_t;

int main()
{
    atomic_map_t m;

    m[4] = 456;
    m[2] = 45678;

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

    return 0;
}

-2

여기서는 std::map사용 관점 에서 단순화 된 예제 중 하나와 약간 유사합니다 .

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;
}

다음과 같이 사용하십시오.

auto keys = getKeys(yourMap);

2
이 답변이 오래되었다는 것도 알고 있습니다. size로 초기화 map.size()하면 벡터 크기 반환이 두 배가됩니다. 다른 사람이 두통을 구하기 위해 고쳐주세요 :(
thc

-3

(왜 std :: map에 멤버 함수가 포함되어 있지 않은지 항상 궁금합니다.)

할 수있는 것보다 더 잘 할 수 없기 때문입니다. 메소드의 구현이 자유 함수의 구현보다 우월하지 않다면 일반적으로 메소드를 작성해서는 안됩니다. 무료 기능을 작성해야합니다.

어쨌든 그것이 왜 유용한 지 즉시 명확하지 않습니다.


8
라이브러리에 "배터리 포함"기능 및 일관된 캡슐화 된 API와 같은 방법을 제공하는 효율성 이외의 이유가 있습니다. 물론 이러한 용어들 중 어느 것도 STL을 잘 설명하지는 않지만 :) Re. 그것이 왜 유용한 지 명확하지 않습니다-정말로? 사용 가능한 키를 나열하는 것이 맵 / 딕 트로 할 수있는 유용한 이유 인 것이 분명합니다. 키는 사용하는 대상에 따라 다릅니다.
andybuckley

4
이 추론 empty()으로 구현할 수 있기 때문에 우리는 가지고 있지 않아야합니다 size() == 0.
gd1

1
@ gd1이 말한 것. 클래스에 많은 기능 중복성이 없어서는 안되지만, 적어도 C ++이 무료 함수를 메소드에 "축복"시킬 수있을 때까지 절대 0을 요구하는 것은 좋은 아이디어가 아닙니다.
einpoklum

1
이전 버전의 C ++에는 empty () 및 size ()가 다른 성능 보증을 제공 할 수있는 컨테이너가 있었으며이를 허용하기에 사양이 충분히 느슨하다고 생각합니다 (특히, 일정한 시간 splice ()를 제공하는 링크 된 목록) . 따라서 이들을 분리하는 것이 합리적이었습니다. 그러나이 불일치가 더 이상 허용되지 않는다고 생각합니다.
DrPizza

나는 동의한다. C ++은 std::map<T,U>쌍의 컨테이너로 취급 됩니다. 파이썬에서는 dict반복 될 때 키처럼 작동하지만 d.items()C ++ 동작을 얻는다고 말할 수 있습니다 . 파이썬도 제공합니다 d.values(). std::map<T,U>확실히 키와 값 을 가지고 있고 반복자를 제공 하는 객체를 반환하는 keys()values()메소드를 제공 할 수 있습니다. begin()end()
Ben
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.