2015-06-17 15 views
6

Tôi có một unordered_map tìm kiếm như thế này:Tìm tất cả các phím tương ứng với cùng một giá trị trong std :: unordered_map

std::unordered_map<int, std::string> theMap2 = {{1,"a"}, {2,"b"}, {3,"c"}, {4,"a"}}; 

Tôi muốn tìm tất cả các phím có cùng một giá trị cho phép nói "a". Bất kỳ đề xuất nào bên cạnh cách rõ ràng:

std::vector<int> arrKeys; 
std::string value = "a"; 
for (const auto& element : theMap) 
    if (element.second == value) 
     arrKeys.push_back(element.first); 
+0

Câu trả lời bằng copy_if đi đâu? Tất cả những gì bạn phải làm là thay đổi lambda để nắm bắt giá trị bằng & thay đổi tham số tự động thành const auto & – KABoissonneault

+0

@KABoissonneault Không, bạn cũng cần điều chỉnh trình lặp đầu ra, vì 'copy_if' sẽ cố gắng sao chép khóa-giá trị * đôi*. – dyp

+0

@dyp Có thể dễ dàng điều chỉnh không? Nếu có, bạn có thể đăng câu trả lời không? – KABoissonneault

Trả lời

9

Tôi nghĩ cách "rõ ràng" thật tuyệt vời: đơn giản, ngắn và dễ đọc.

Một tùy chọn khác là sử dụng thuật toán stl. Những gì bạn cần là thuật toán transform_if để bạn có thể nói:

std::transform_if(std::begin(theMap), std::end(theMap), std::back_inserter(arrKeys), check_value, get_value); 

nhưng không có stl. Những gì tôi có thể đề nghị là:

std::vector<int> arrKeys; 
std::string value = "a"; 

auto check_value = [&](std::pair<const int, std::string> const& p)->bool 
{ 
    return (p.second == value); 
}; 

auto end = std::end(theMap); 
auto it = find_if(std::begin(theMap), end, check_value); 
while (it != end) 
{ 
    arrKeys.push_back(it->first); 
    it = find_if(std::next(it), end, check_value); 
} 
+0

Tôi nghĩ bạn đề xuất copy_if để tạo bản đồ mới chỉ với các giá trị mong muốn, sau đó chuyển đổi để điền vào arrKeys. ý tưởng của bạn là gì? – Aahzbg

+0

Xin lỗi, tôi đã bị phân tâm bởi vị từ và không chú ý đến vấn đề chuyển đổi cặp khóa-giá trị thành giá trị. Trong khi 'copy_if' vẫn có thể được sử dụng thông qua các bộ điều hợp lặp, thì một' biến_'' có lẽ là hợp lý hơn. – dyp

+0

@dyp Bạn không cần phải viết một cái gì đó như 'back_first_inserter' cho' copy_if? – Barry

2

More ra quan tâm hơn bất cứ điều gì khác, tôi đã viết một wrapper cơ bản mà có thể được sử dụng cho copy_if. Nó giống như std::back_inserter, nhưng thay vì chỉ chèn đối tượng, nó chèn std::get<N>(obj). Điều này làm cho nó có thể sử dụng cho std::array, std::tuplestd::pair.

Để chèn pair.first, như chúng tôi muốn trong ví dụ này, chúng tôi sử dụng back_n_inserter<0>.

template< std::size_t N, class Container > 
class back_n_insert_iterator : public std::iterator< std::output_iterator_tag, 
                 void, void, void, void > 
{ 
public: 
    back_n_insert_iterator (Container& c) : c{c} {}; 

    //could protect this by checking that the get call is_convertible to the value_type 
    template <typename T> 
    decltype(auto) operator= (T&& collec) 
    { 
     c.push_back(std::get<N>(std::forward<T>(collec))); 
     return *this; 
    } 

    decltype(auto) operator*() { return *this; } 
    decltype(auto) operator++() { return *this; } 
    decltype(auto) operator++ (int) { return *this; } 
private: 
    Container& c; 
}; 

template< std::size_t N, class Container > 
back_n_insert_iterator<N,Container> back_n_inserter(Container& c) 
{ 
    return {c}; 
} 

Bây giờ chúng ta có thể sử dụng bộ chuyển đổi của chúng tôi trong một cuộc gọi copy_if:

std::copy_if(theMap.begin(), theMap.end(), 
      back_n_inserter<0>(arrKeys), 
      [&value](const auto& el){return el.second == value;}); 

Nhờ @dyp cho tất cả các lời đề nghị.

+1

Bạn có thể tăng cường 'back_first_inserter' thành' back_n_inserter' nếu bạn bỏ hạn chế tham số hàm thông qua khớp mẫu; 'template void operator = (T && t) {c.push_back (std :: get (std :: forward (t))); } '(có thể được bảo vệ bởi SFINAE). Tôi vẫn không tin rằng đây là một ý tưởng tốt hơn là viết một 'transform_if', btw. Với phạm vi của Niebler v3, bạn có thể viết một cái gì đó như 'std :: vector arrKeys = theMap | xem :: remove_if ([&] (tự động const & p) {return p.second! = value;}) | xem :: phím; '(không được kiểm tra) – dyp

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