지도에 대한 나만의 비교기를 어떻게 만들 수 있습니까?


87
typedef map<string, string> myMap;

에 새 쌍을 삽입 할 때 myMapstring를 사용하여 자체 문자열 비교기로 비교합니다. 해당 비교기를 재정의 할 수 있습니까? 예를 들어 string알파벳이 아닌 길이로 키를 비교하고 싶습니다 . 아니면지도를 정렬하는 다른 방법이 있습니까?

답변:


142

std::map최대 4 개의 템플릿 유형 인수를 사용하며 세 번째는 비교기입니다. 예 :

struct cmpByStringLength {
    bool operator()(const std::string& a, const std::string& b) const {
        return a.length() < b.length();
    }
};

// ...
std::map<std::string, std::string, cmpByStringLength> myMap;

또는 maps constructor에 비교기를 전달할 수도 있습니다 .

그러나 길이로 비교할 때 맵에서 각 길이의 문자열 하나만 키로 가질 수 있습니다.


4
중복 된 키를 포함하려면 멀티 맵을 사용할 수 있습니다.
Xitrum 2011

@GeorgFritzsche 생성자에게 비교자를 전달하는 예제를 제공 할 가능성이 있습니까?
bpeikes

1
@bpeikes : 너무 다른 보이지 않는 :std::map<std::string, std::string> myMap(cmpByStringLength());
게오르그 FRITZSCHE

std :: map <int, int>에 문제가 있었고 일부는 순서가 증가하고 다른 일부는 순서가 감소했습니다. std :: map <int, int, std :: greater> 및 std :: map <int, int, std :: less>를 사용하고 싶지 않았습니다. 다른 순서로 정렬 된 맵을 사용할 수 없기 때문입니다. 모든 것을 템플릿으로 만들지 않는 한 단일 함수에 대한 매개 변수로. 다음을 수행해야한다는 것을 알았습니다. typedef std :: map <int, int, (bool) * (int, int)> mymap; 그런 다음 기능을 전달할 수있었습니다. 다음을 시도했지만 작동하지 않습니다. typedef std :: map <int, int> mymap; mymap map1 (std :: less); mymap map2 (std :: greater);
bpeikes

2
@GeorgFritzsche는 : 생성자의 인수로, 생성자에 비교기를 전달하는 그하지 않습니다 작품은 비교 형의 인스턴스,해야 cmpByStringLength의 인스턴스가 아닌 std::less<std::string>. 생성자의 모든 비교기 세트를 가질 수 있습니다 일반적인지도를 들어, 같은 것을 필요std::map<std::string, std::string, std::function<bool(const std::string &, const std::string &)>> myMap(cmpByStringLength);
크리스 도드

22

C ++ 11 이후 로 비교기 구조체를 정의하는 대신 람다 식을 사용할 수도 있습니다 .

auto comp = [](const string& a, const string& b) { return a.length() < b.length(); };
map<string, string, decltype(comp)> my_map(comp);

my_map["1"]      = "a";
my_map["three"]  = "b";
my_map["two"]    = "c";
my_map["fouuur"] = "d";

for(auto const &kv : my_map)
    cout << kv.first << endl;

산출:

1
2
3
fouuur

Georg의 답변에 대한 마지막 메모를 반복하고 싶습니다. 길이로 비교할 때 맵에서 각 길이의 문자열 하나만 키로 가질 수 있습니다.

Ideone의 코드


12

예,의 세 번째 템플릿 매개 변수 map는 이진 술어 인 비교기 를 지정합니다. 예:

struct ByLength : public std::binary_function<string, string, bool>
{
    bool operator()(const string& lhs, const string& rhs) const
    {
        return lhs.length() < rhs.length();
    }
};

int main()
{
    typedef map<string, string, ByLength> lenmap;
    lenmap mymap;

    mymap["one"] = "one";
    mymap["a"] = "a";
    mymap["fewbahr"] = "foobar";

    for( lenmap::const_iterator it = mymap.begin(), end = mymap.end(); it != end; ++it )
        cout << it->first << "\n";
}

11
왜 파생 std::binary_function됩니까? 필요합니까?
Devolus

12
std::binary_function이 답변은 아마도 업데이트를 사용할 수 있도록 C ++ 17에서 제거되었습니다.
Dan Olson

1

비교 함수에 대한 포인터 유형을지도에 세 번째 유형으로 지정하고지도 생성자에 대한 함수 포인터를 제공합니다.
map<keyType, valueType, typeOfPointerToFunction> mapName(pointerToComparisonFunction);

(A)에 비교 함수를 제공하기 위해 아래의 예에서 보면 받아 map함께 vector키 같이 반복자 int값으로한다.

#include "headers.h"

bool int_vector_iter_comp(const vector<int>::iterator iter1, const vector<int>::iterator iter2) {
    return *iter1 < *iter2;
}

int main() {
    // Without providing custom comparison function
    map<vector<int>::iterator, int> default_comparison;

    // Providing custom comparison function
    // Basic version
    map<vector<int>::iterator, int,
        bool (*)(const vector<int>::iterator iter1, const vector<int>::iterator iter2)>
        basic(int_vector_iter_comp);

    // use decltype
    map<vector<int>::iterator, int, decltype(int_vector_iter_comp)*> with_decltype(&int_vector_iter_comp);

    // Use type alias or using
    typedef bool my_predicate(const vector<int>::iterator iter1, const vector<int>::iterator iter2);
    map<vector<int>::iterator, int, my_predicate*> with_typedef(&int_vector_iter_comp);

    using my_predicate_pointer_type = bool (*)(const vector<int>::iterator iter1, const vector<int>::iterator iter2);
    map<vector<int>::iterator, int, my_predicate_pointer_type> with_using(&int_vector_iter_comp);


    // Testing 
    vector<int> v = {1, 2, 3};

    default_comparison.insert(pair<vector<int>::iterator, int>({v.end(), 0}));
    default_comparison.insert(pair<vector<int>::iterator, int>({v.begin(), 0}));
    default_comparison.insert(pair<vector<int>::iterator, int>({v.begin(), 1}));
    default_comparison.insert(pair<vector<int>::iterator, int>({v.begin() + 1, 1}));

    cout << "size: " << default_comparison.size() << endl;
    for (auto& p : default_comparison) {
        cout << *(p.first) << ": " << p.second << endl;
    }

    basic.insert(pair<vector<int>::iterator, int>({v.end(), 0}));
    basic.insert(pair<vector<int>::iterator, int>({v.begin(), 0}));
    basic.insert(pair<vector<int>::iterator, int>({v.begin(), 1}));
    basic.insert(pair<vector<int>::iterator, int>({v.begin() + 1, 1}));

    cout << "size: " << basic.size() << endl;
    for (auto& p : basic) {
        cout << *(p.first) << ": " << p.second << endl;
    }

    with_decltype.insert(pair<vector<int>::iterator, int>({v.end(), 0}));
    with_decltype.insert(pair<vector<int>::iterator, int>({v.begin(), 0}));
    with_decltype.insert(pair<vector<int>::iterator, int>({v.begin(), 1}));
    with_decltype.insert(pair<vector<int>::iterator, int>({v.begin() + 1, 1}));

    cout << "size: " << with_decltype.size() << endl;
    for (auto& p : with_decltype) {
        cout << *(p.first) << ": " << p.second << endl;
    }

    with_typedef.insert(pair<vector<int>::iterator, int>({v.end(), 0}));
    with_typedef.insert(pair<vector<int>::iterator, int>({v.begin(), 0}));
    with_typedef.insert(pair<vector<int>::iterator, int>({v.begin(), 1}));
    with_typedef.insert(pair<vector<int>::iterator, int>({v.begin() + 1, 1}));

    cout << "size: " << with_typedef.size() << endl;
    for (auto& p : with_typedef) {
        cout << *(p.first) << ": " << p.second << endl;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.