मैं मानचित्र के लिए अपना तुलनित्र कैसे बना सकता हूं?


87
typedef map<string, string> myMap;

जब एक नई जोड़ी डालते हैं myMap, तो यह stringअपने स्वयं के स्ट्रिंग तुलनित्र द्वारा तुलना करने के लिए कुंजी का उपयोग करेगा । क्या उस तुलनित्र को ओवरराइड करना संभव है? उदाहरण के लिए, मैं stringइसकी लंबाई की तुलना वर्णमाला से करना चाहता हूं । या मानचित्र को छाँटने का कोई और तरीका है?

जवाबों:


142

std::mapचार टेम्पलेट प्रकार तर्क तक ले जाता है, तीसरा एक तुलनित्र है। उदाहरण के लिए:

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 कम्प्रेसर के लिए एक तुलनित्र भी पास कर सकते हैं ।

ध्यान दें कि जब लंबाई से तुलना की जाती है तो आप एक कुंजी के रूप में नक्शे में प्रत्येक लंबाई के केवल एक तार हो सकते हैं।


4
ध्यान दें कि यदि हम डुप्लिकेट की को शामिल करना चाहते हैं तो हम मल्टीमैप का उपयोग कर सकते हैं
Xitrum

@GeorgFritzsche कोई भी मौका जिससे आप कंस्ट्रक्टर के लिए संधारित्र पास करने का एक उदाहरण प्रदान करते हैं?
बाइक 21

1
@ बाइक: यह बहुत अलग नहीं लगता:std::map<std::string, std::string> myMap(cmpByStringLength());
जॉर्ज फ्रिट्ज़

मेरे पास एक std :: map <int, int>, कुछ बढ़ते हुए क्रम के साथ और अन्य घटते क्रम के साथ एक समस्या थी। मैं std :: map <int, int, std :: बड़ा> और std :: map <int, int, std :: less> का उपयोग नहीं करना चाहता था क्योंकि तब मैं उन मानचित्रों का उपयोग नहीं कर सकता था जो अलग-अलग क्रमों में क्रमबद्ध थे। जब तक मैंने सब कुछ एक खाका नहीं बना लिया, तब तक एक ही फ़ंक्शन के पैरामीटर के रूप में। मैंने पाया कि मुझे निम्न कार्य करना था: टाइपडिफ std :: मानचित्र <int, int, (बूल) * (int, int)> मायमैप; तब मैं फ़ंक्शंस में पास होने में सक्षम था। मैंने निम्नलिखित की कोशिश की, लेकिन यह काम नहीं करेगा: typedef std :: map <int, int> mymap; mymap map1 (std :: less); mymap map2 (std :: बड़ा);
बाइक

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
दो
तीन
फौउर

मैं जॉर्ज के उत्तर के अंतिम नोट को दोहराना चाहूंगा: जब लंबाई की तुलना करते हैं, तो आप एक कुंजी के रूप में नक्शे में प्रत्येक लंबाई के केवल एक स्ट्रिंग हो सकते हैं।

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? क्या इसकी जरूरत है?
देवोलस

12
std::binary_functionc ++ 17 में हटा दिया गया है, इसलिए यह उत्तर शायद अद्यतन का उपयोग कर सकता है।
डैन ओल्सन

1

मानचित्र में 3 प्रकार के रूप में अपने तुलनात्मक फ़ंक्शन के लिए पॉइंटर के प्रकार को निर्दिष्ट करें, और फ़ंक्शन पॉइंटर को मानचित्र निर्माता को प्रदान करें:
map<keyType, valueType, typeOfPointerToFunction> mapName(pointerToComparisonFunction);

एक के लिए एक तुलना समारोह प्रदान करने के लिए नीचे दिए गए उदाहरण पर नज़र डालें 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;
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.