2015-09-03 13 views
5

Hãy nói rằng chúng tôi có std::set<int> và chúng tôi muốn tạo ra một std::vector<int> với tất cả các giá trị từ bộ rằng:Khởi tạo một container với phạm vi iterator của container với loại khác nhau

std::set<int> set; 
std::vector<int> vec(set.begin(), set.end()); 

Đây là đơn giản và thanh lịch. Nhưng giả sử tôi có số std::map<std::string,int> và tôi muốn sao chép tất cả các giá trị sang std::vector<int>. Thật không may là không có hàm tạo nào, chấp nhận phạm vi của các trình vòng lặp và hàm chuyển đổi. Tại sao không có nhà xây dựng như vậy được cung cấp? Có một cách đơn giản và thanh lịch để khởi tạo một container với các giá trị kiểu khác nhau?

Trả lời

5

Sử dụng chuyển đổi lặp:

#include <boost/iterator/transform_iterator.hpp> 
#include <vector> 
#include <map> 

int main() { 
    std::map<int, double> m; 
    auto f = [](auto&& pair) { return pair.second; }; 
    std::vector<double>(boost::make_transform_iterator(m.begin(), f), 
         boost::make_transform_iterator(m.end(), f)); 
} 

Ngoài ra, sử dụng tăng :: adapter:

#include <boost/range/adaptor/map.hpp> 
#include <vector> 
#include <map> 

int main() { 
    std::map<int, double> m; 
    auto range = boost::adaptors::values(m); 
    std::vector<double>(range.begin(), range.end()); 
} 

Hoặc giống như trên:

auto v = boost::copy_range<std::vector<double> >(boost::adaptors::values(m)); 

Lưu ý rằng việc sử dụng hàm tạo dải của vector hiệu quả hơn giải pháp liên quan đến back_inserter.

+1

Cá nhân, tôi thích toán tử "đường ống" hơn khi sử dụng bộ điều hợp tăng cường 'phạm vi tự động = m | boost :: adapters :: values; ' – Alan

+0

@Alan Tôi thích toán tử gọi hàm cho các cuộc gọi hàm, và nó ngắn hơn để gõ (' | 'vs'() '). –

0

Tôi nghĩ tốt nhất bạn có thể làm là sử dụng các chu kỳ dựa trên phạm vi hoặc chức năng for_each.

1

std::map có mô hình bộ nhớ khác, lưu trữ giá trị là std::pair. Giải nén những thứ này không phải là công việc của một nhà xây dựng. Bạn có thể tạo véc tơ, reserve bộ nhớ bằng bản đồ sizeiterate trên các cặp bản đồ để đẩy các số nguyên của bạn vào mặt sau vectơ của bạn. std::transform cắt điều đó.

+0

'std :: set' cũng có một mô hình bộ nhớ khác, điều đó không ngăn cản tôi bắt đầu một vectơ từ phạm vi của nó. – Slava

+0

Bởi vì các trình vòng lặp thiết lập của bạn chỉ trả về bộ đệm dự kiến, một bản đồ trả về một cặp không thể được đúc thành đầu ra mong đợi. – Youka

2

Với boost::transform_iterator:

#include <functional> 
#include <boost/iterator/transform_iterator.hpp> 

std::map<std::string, int> m{ {"a", 1}, {"b", 2} }; 
auto second = std::mem_fn(&std::map<std::string, int>::value_type::second); 

std::vector<int> vec(boost::make_transform_iterator(std::begin(m), second) 
        , boost::make_transform_iterator(std::end(m), second)); 

DEMO

+0

Có lẽ downvoter (không phải tôi) chưa có thời gian để viết bình luận và vẫn viết nó –

+0

Không phải tôi, nhưng gọi qua 'std :: mem_fn' có thể sẽ không được inlined. –

+1

@AaronMcĐược rồi, đó sẽ là một lời bình luận khá dài chết tiệt – Slava

Các vấn đề liên quan