2009-02-11 13 views
26

Tôi biết tìm phương thức tìm khóa được cung cấp trong std :: map và trả về trình lặp cho phần tử. Có anyway để tìm giá trị và nhận được một iterator để các yếu tố? Những gì tôi cần làm là để kiểm tra giá trị quy định tồn tại trong std :: map. Tôi đã làm điều này bằng cách lặp lại tất cả các mục trong bản đồ và so sánh. Nhưng tôi muốn biết là có cách tiếp cận nào tốt hơn cho việc này không.Kiểm tra giá trị tồn tại trong một tiêu chuẩn :: bản đồ - C++

Dưới đây là những gì tôi đã viết

bool ContainsValue(Type_ value) 
{ 
    bool found = false; 
    Map_::iterator it = internalMap.begin(); // internalMap is std::map 
    while(it != internalMap.end()) 
    { 
     found = (it->second == value); 
     if(found) 
      break; 
     ++it; 
    } 
    return found; 
} 

Sửa

Làm thế nào về việc sử dụng một bản đồ nội bộ mà các cửa hàng giá trị, tổ hợp phím. Vì vậy, tôi có thể gọi tìm thấy trên nó? Có phải tìm() trong std :: bản đồ đang tìm kiếm tuần tự không?

Cảm ơn

Trả lời

19

Bạn có thể sử dụng boost::multi_index để tạo bidirectional map - bạn có thể sử dụng giá trị của cặp làm khóa để thực hiện tra cứu nhanh.

+0

bạn đánh tôi với nó :) Câu trả lời hay. –

2

Không, bạn phải lặp qua std :: ánh xạ và kiểm tra tất cả các giá trị theo cách thủ công. Tùy thuộc vào những gì bạn muốn làm, bạn có thể bọc std :: map trong một lớp đơn giản cũng lưu trữ tất cả các giá trị được chèn vào bản đồ trong một cái gì đó dễ dàng tìm kiếm và không cho phép trùng lặp, như một tiêu chuẩn ::bộ. Không kế thừa từ bản đồ std :: (nó không có một destructor ảo!), Nhưng quấn nó để bạn có thể làm một cái gì đó như thế này:

WrappedMap my_map< std::string, double >; 
my_map[ "key" ] = 99.0; 
std::set<double> values = my_map.values(); // should give back a set with only 99.0 in it 

Một lựa chọn thay thế để tự làm của bạn sẽ là sử dụng bản đồ Tăng tốc hai chiều, có thể dễ dàng tìm thấy trong các bài đăng bên dưới hoặc bởi Google.

Nó thực sự phụ thuộc vào những gì bạn muốn làm, tần suất bạn muốn làm và mức độ khó khăn khi cuộn lớp đóng gói nhỏ của riêng bạn so với cài đặt và sử dụng Boost. Tôi thích Boost, vì vậy đó là một cách tốt để đi - nhưng có một cái gì đó tốt đẹp và đầy đủ về làm cho lớp wrapper của riêng bạn. Bạn có lợi thế của sự hiểu biết trực tiếp sự phức tạp của các hoạt động, và bạn có thể không cần ánh xạ ngược đầy đủ các giá trị => các khóa được cung cấp bởi bản đồ hai chiều Tăng cường.

+0

Anh ấy muốn một trình lặp cho phần tử, vì vậy bạn muốn sử dụng bản đồ thứ hai <> thay vì tập hợp <>. –

14

Cách sử dụng một bản đồ khác trong nội bộ lưu trữ giá trị, kết hợp khóa. Vì vậy, tôi có thể gọi tìm thấy trên nó?

Có: duy trì hai bản đồ, với một bản đồ bằng cách sử dụng một loại khóa và một bằng cách sử dụng phím kia.

Tìm() trong std :: map đang tìm kiếm tuần tự?

Không có tìm kiếm nhị phân của cây được sắp xếp: tốc độ của nó là O (log (n)).

+0

Điều đó có ý nghĩa. Vì vậy, sẽ duy trì hai bản đồ cho hiệu suất tốt hơn so với tuần tự tìm kiếm và tìm kiếm giá trị, phải không? –

+3

Sẽ mất hai lần để chèn hoặc xóa bất kỳ thứ gì (sử dụng hai bản đồ thay vì một bản đồ); nhưng đối với một số lượng lớn các yếu tố, việc tìm kiếm sẽ nhanh hơn rất nhiều vì O (log (n)) nhỏ hơn nhiều so với O (n) cần thiết cho việc tìm kiếm tuần tự. – ChrisW

+0

Tuyệt vời Chris. Cảm ơn. –

15

Nếu bạn có quyền truy cập thư viện xuất sắc boost thì bạn nên sử dụng boost::multi_index để tạo bidirectional map như Mark cho biết. Không giống như std :: map cho phép bạn tra cứu bằng khóa hoặc giá trị.

Nếu bạn chỉ có STL trao đoạn mã sau sẽ làm các trick (templated để làm việc với bất kỳ loại đồ nơi mapped_type hỗ trợ toán tử ==):

#include <map> 
#include <string> 
#include <algorithm> 
#include <iostream> 
#include <cassert> 

template<class T> 
struct map_data_compare : public std::binary_function<typename T::value_type, 
                 typename T::mapped_type, 
                 bool> 
{ 
public: 
    bool operator() (typename T::value_type &pair, 
        typename T::mapped_type i) const 
    { 
     return pair.second == i; 
    } 
}; 


int main() 
{ 
    typedef std::map<std::string, int> mapType; 

    mapType map; 

    map["a"] = 1; 
    map["b"] = 2; 
    map["c"] = 3; 
    map["d"] = 4; 
    map["e"] = 5; 

    const int value = 3; 

    std::map<std::string, int>::iterator it = std::find_if(map.begin(), map.end(), std::bind2nd(map_data_compare<mapType>(), value)); 

    if (it != map.end()) 
    { 
     assert(value == it->second); 
     std::cout << "Found index:" << it->first << " for value:" << it->second << std::endl; 
    } 
    else 
    { 
     std::cout << "Did not find index for value:" << value << std::endl; 
    } 
} 
-3

thể mà tôi không hoàn toàn hiểu những gì bạn đang cố gắng hoàn thành. Nhưng để chỉ đơn giản là kiểm tra xem bản đồ có chứa một giá trị hay không, tôi tin rằng bạn có thể sử dụng số được xây dựng trong find.

bool ContainsValue(Type_ value) 
{ 
    return (internalMap.find(value) != internalMap.end()); 
} 
+6

'std :: map :: find' tìm kiếm theo khóa, anh ấy đang tìm kiếm theo giá trị. – Dennis

+0

Bạn hoàn toàn đúng. Tôi đoán ngắn lặp lại và tìm kiếm bản đồ bằng tay, bạn nên sử dụng bản đồ hai chiều như Boost.MultiIndex đã được đề xuất. – Ternary

4

thử chức năng này:

template <class Map, class Val> typename Map::const_iterator MapSearchByValue(const Map & SearchMap, const Val & SearchVal) 
{ 
    Map::const_iterator iRet = SearchMap.end(); 
    for (Map::const_iterator iTer = SearchMap.begin(); iTer != SearchMap.end(); iTer ++) 
    { 
     if (iTer->second == SearchVal) 
     { 
      iRet = iTer; 
      break; 
     } 
    } 
    return iRet; 
} 

tôi nghĩ rằng đó là hữu ích

+2

Sửa tôi nếu tôi sai nhưng không phải đây chỉ là mã trong câu hỏi? –

+2

@JonathanMee Bạn không sai. –

0

gì bạn đang yêu cầu chính xác là những gì std::find không (không phải là hàm thành viên)

template< class InputIt, class T > 
InputIt find(InputIt first, InputIt last, const T& value); 
0

Không phải là một lựa chọn tốt nhất nhưng có thể hữu ích trong vài trường hợp người dùng gán giá trị mặc định như 0 hoặc NULL tại init ialization.

Ex. 
< int , string > 
< string , int > 
< string , string > 

consider < string , string > 
mymap["1st"]="first"; 
mymap["second"]=""; 
for (std::map<string,string>::iterator it=mymap.begin(); it!=mymap.end(); ++it) 
{ 
     if (it->second =="") 
      continue; 
}