2011-11-08 34 views
8

Tôi muốn sử dụng std :: find_if để tìm kiếm phần tử đầu tiên trong bản đồ có giá trị nhất định trong một phần tử cụ thể của cấu trúc giá trị của nó. Tôi là một chút bối rối mặc dù. Tôi nghĩ rằng tôi cần phải sử dụng bind1st hoặc bind2nd, nhưng tôi không tích cực đó là đúng cách để đi.std :: map find_if nhầm lẫn kiểu trạng thái

Dưới đây là một số mã giả:

struct ValueType { int x, int y, int z }; 

std::map<int, ValueType> myMap; 

... {populate map} 

std::map<int, ValueType>::iterator pos = std::find_if(myMap.begin(), myMap.end(), <?>); 

Vì vậy, chúng ta hãy nói rằng tôi muốn tìm phần tử đầu tiên của bản đồ, nơi các thành viên .x của ValueType là tương đương với một giá trị số nguyên nào đó (mà có thể thay đổi từng cuộc gọi).

Cách tốt nhất để viết hàm hoặc đối tượng hàm để đạt được điều này là gì? Tôi hiểu rằng đó phải là một biến vị ngữ đơn nhất làm cho tôi nghĩ rằng tôi sẽ cần bind1st hoặc bind2nd để cung cấp giá trị số nguyên mà tôi đang kiểm tra, nhưng tôi không chắc chắn làm thế nào để đi về nó. Đã quá lâu rồi kể từ khi tôi nhìn vào thứ này! >. <

Trả lời

15

Các yếu tố trong bản đồ không được sắp xếp theo giá trị, chúng được sắp xếp theo khóa. Vì vậy, cụm từ "yếu tố đầu tiên" không có ý nghĩa nhiều.

Để tìm một số phần tử (không phải là đầu tiên) có x bằng một số giá trị mà bạn có thể viết các functor như sau:

struct check_x 
{ 
    check_x(int x) : x_(x) {} 
    bool operator()(const std::pair<int, ValueType>& v) const 
    { 
    return v.second.x == x_; 
    } 
private: 
    int x_; 
}; 

Sau đó, sử dụng nó như sau:

// find any element where x equal to 10 
std::find_if(myMap.begin(), myMap.end(), check_x(10)); 
+3

Kể từ khi các yếu tố trong bản đồ đều được sắp xếp theo mã, thứ tự các mục là rõ ràng, và yêu cầu người đầu tiên thực hiện một điều kiện là như vậy, cũng được xác định rõ. – celtschk

+0

Có, nó được xác định rõ. Nhưng thứ tự không phụ thuộc vào giá trị của ValueType. Đó là điều tôi đang cố nói. –

+0

Cảm ơn, chính xác những gì tôi cần :) –

3
struct Pred 
{ 
    Pred(int x) : x_(x) { } 
    bool operator()(const std::pair<int, ValueType>& p) 
    { 
     return (x_ == p.second.x); 
    } 
private: 
    int x_; 
}; 

... = std::find_if(myMap.begin(), myMap.end(), Pred(NUMBER)); 
1

Nếu bạn muốn tìm kiếm trong các giá trị thì có thể tốt hơn để sử dụng Boost Bimap để không bị chậm?

11

Bạn có thể sử dụng một hàm lambda

int val = ...; 
auto it = std::find_if(myMap.begin(), myMap.end(), 
    [val](const std::pair<int, ValueType> & t) -> bool { 
     return t.second.x == val; 
    } 
); 

Nhưng như Kirill V. Lyadvinsky câu trả lời cho thấy các yếu tố "đầu tiên" có thể không phải những gì bạn mong đợi.

1

Điều này không có liên quan gì với std::bind1st hoặc std::bind2nd. Trước hết, bạn phải ghi nhớ rằng các yếu tố của bản đồ là cặp khóa-giá trị, trong trường hợp của bạn là std::pair<int,ValueType>. Sau đó, bạn chỉ cần một vị ngữ so sánh thành viên x của thành viên thứ hai của yuch một cặp chống lại một giá trị cụ thể:

struct XEquals : std::unary_function<std::pair<int,ValueType>,bool> 
{ 
    XEquals(int _x) 
     : x(_x) {} 
    bool operator()(const std::pair<int,ValueType> &v) const 
     { return p.second.x == x; } 
    int x; 
}; 
1

sử dụng Boost.BindBoost.Lambda:

... 
#include <boost/bind.hpp> 
#include <boost/lambda/lambda.hpp> 
... 
typedef std::map<int, ValueType> MapType; 
... 
MapType::iterator pos = std::find_if(myMap.begin(), myMap.end(), 
    boost::bind(&ValueType::y, boost::bind(&MapType::iterator::value_type::second, _1)) == magic_number); 
1

Xây dựng trên tất cả các câu trả lời ở trên tôi lừa bằng cách sử dụng decltype với ngữ nghĩa C++ 11.

auto beg_ = myMap.begin(); 
auto end_ = myMap.end(); 
auto it = find_if(beg_, end_, 
    [&some_val](decltype(*beg_) & vt) { 
     return vt.second == some_val;}); 
if (end_ != it) { 
    auto key_found = (*it).first; 
} else { 
    // throw error not found. 
}