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_type로 auto.


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.