2011-10-05 64 views
10
map<T,Z> m= ...; 
vector<T> v; 
v.reserve(m.size); 
for(map<T,Z>::iterator it=m.begin();it!=m.end();++it) 
{ 
v.push_back(it->first); 
} 

有沒有使用一些STL功能的一個更好的1行版本?使用STL從地圖填充矢量<T><T,Z>的鑰匙

編輯:不是使用C++ 11!

+2

矯枉過正?無論如何,你並沒有輸入太多的代碼來實現這一點。 –

+0

@Als:通過這個邏輯,很多std ::算法同樣沒用。 –

+0

@Mahesh - 我正在考慮一些後插入魔法,或者其他什麼 –

回答

8

便攜:

struct SelectKey { 
    template <typename F, typename S> 
    F operator()(const std::pair<const F, S> &x) const { return x.first; } 
}; 

std::transform(m.cbegin(), m.cend(), std::back_inserter(v), SelectKey()); 

我認爲STL的一些實現有一個非標準擴展名爲select1st,這是這裏顯示的SelectKey相當。正如K-Ballo在評論中指出的那樣,還有一個TR1版本。我喜歡這個明確命名的版本,因爲它更容易看到發生了什麼。

由於沒有必要的狀態,您可以通過使用一個實際的功能,而不是一個函子逃脫略少的樣板:

template <typename F, typename S> 
F SelectKey()(const std::pair<const F, S> &x) { return x.first; } 

std::transform(m.cbegin(), m.cend(), std::back_inserter(v), SelectKey); 

如果你可以用C++ 11,你可以使用拉姆達,這使選擇代碼接近它的使用,其中:

std::transform(m.cbegin(), m.cend(), std::back_inserter(v), 
       [](const std::pair<const F, S> &x) { return x.first; }); 

甚至範圍爲基礎的循環,這可能是最優雅和可讀性:

for(const auto &x : m) { 
    v.push_back(x.first); 
} 
+1

lambda怎麼樣?這將是真正的一線。 – Dani

+2

你的'operator()'應該是'const'。在TR1中,這可以通過'std :: bind(&map < T, Z > :: value_type :: first,_1)'來實現。 –

+3

不應該模擬結構,而應該使用'operator()'。如果你真的想對結構進行模板化,你應該在創建它時提供參數:'SelectKey ()'。 – Xeo

2

在C++ 11,你可以使用lambda表達式:

typedef std::map< std::string, std::string > map_t; 
map_t map; 
std::vector<std::string> v; 

std::for_each(map.begin(), map.end(), [&v](map_t::value_type const& it) 
     { 
      v.push_back(it.first); 
     }); 
4

預C++ 11,你可以使用轉換和自定義功能結構:

template <class K, class V> 
struct key_selector : std::unary_function<const std::pair<K, V>&, const K&> 
{ 
    const K& operator()(const std::pair<K, V>& element) const 
    { 
     return element.first; 
    } 
}; 

transform(m.begin(), m.end(), back_inserter(v), key_selector<T,Z>()); 

如果你有進入升壓或TR1,您可以將其替換key_selectormem_fn

transform(m.begin(), m.end(), back_inserter(v), mem_fn(&map<T,Z>::value_type::first)); 

後C++ 11,你可以使用lambda表達式:

transform(m.begin(), m.end(), back_inserter(v), [](const map<T,Z>::value_type& x) {return x.first;}); 
+0

在pre C++ 11中,你不能使用'bind'。如果你依賴非標準的擴展或提升,那就這麼說吧。 –

+0

@Christian:真的,與預C++ 11你可以使用'std :: tr1 :: bind'的警告。 – ildjarn

+0

@ildjarn是的,但他應該這樣說,而不是假裝它是標準的。 –

1

你可以做線沿線的東西:

std::transform(m.begin(), m.end(), std::back_inserter(v), FUNCTOR); 

凡函子依賴於STL或庫,並且您有編譯器的版本。

C++ 11(拉姆達)

std::transform(m.begin(), m.end(), std::back_inserter(v), [](map<T,Z>::const_reference a) { return a.first; }); 

C++ 11(STD ::得到)

std::transform(m.begin(), m.end(), std::back_inserter(v), &std::get<0>); 

C++ SGI STL具有仿函數稱爲select1st可用於

std::transform(m.begin(), m.end(), std::back_inserter(v), select1st); 

使用像其他人一樣的函子對象描述了C++ 03(Not C++ 11)。

相關問題