std :: st_ :: सेट के लिए back_inserter?


94

मुझे लगता है कि यह एक सरल प्रश्न है। मुझे ऐसा कुछ करने की आवश्यकता है:

std::set<int> s1, s2;
s1 = getAnExcitingSet();
std::transform(s1.begin(), s1.end(), std::back_inserter(s2), ExcitingUnaryFunctor());

बेशक, std::back_inserterकाम नहीं करता है क्योंकि वहाँ नहीं है push_backstd::inserterयह भी एक पुनरावृत्ति की जरूरत है? मैंने उपयोग नहीं किया है std::inserterइसलिए मुझे यकीन नहीं है कि मुझे क्या करना है।

क्या किसी को कुछ पता है?


बेशक, मेरा दूसरा विकल्प एक वेक्टर का उपयोग करना है s2, और फिर बाद में इसे सॉर्ट करना है। शायद यह बेहतर है?

जवाबों:


139

setऐसा नहीं है push_backक्योंकि एक तत्व की स्थिति सेट के तुलनित्र द्वारा निर्धारित की जाती है। इसका उपयोग करें std::inserterऔर इसे पास करें .begin():

std::set<int> s1, s2;
s1 = getAnExcitingSet();
transform(s1.begin(), s1.end(), 
          std::inserter(s2, s2.begin()), ExcitingUnaryFunctor());

इंसर्ट करने वाला इटरेटर तब कॉल करेगा, s2.insert(s2.begin(), x)जहां xलिखे जाने पर इटेटर को पास किया गया मान कहां है। सेट एक संकेत के रूप में पुनरावृत्ति का उपयोग करता है जहां सम्मिलित करना है। आप के रूप में अच्छी तरह से उपयोग कर सकते हैं s2.end()


2
चूंकि inserter(vec, vec.end())वैक्टर के लिए काम करता है, इसलिए, कोई भी पहली जगह में back_inserter का उपयोग क्यों करता है?
NHDaly

7
@NHDaly: क्योंकि back_inserter तेज है
मार्टन78

@ marton78 लेकिन क्या यह केवल बहुत कम मार्जिन से तेज नहीं होना चाहिए, अगर बिल्कुल भी? जब किसी तत्व को स्थानांतरित नहीं करना होता है तो वेक्टर के insertबजाय कॉल push_backकरना लगभग समान (O (1)) होना चाहिए।
फेलिक्स डॉम्बेक

3
@FelixDombek आप सही हैं, यह बहुत धीमी नहीं होगी। v.insert(x, v.end())शुरुआत में एक अतिरिक्त शाखा होगी (इसके कारण n तत्व चलते हैं, लेकिन यहाँ n शून्य है)। हालाँकि, inserter1 का उपयोग करना ) push_back2 का उपयोग करने की तुलना में एक अलग आशय का संचार करता है ) असामान्य है और पाठक को रोक देता है और सोचता है कि 3) एक समयपूर्व विराम चिह्न है।
Marton78

0

2016 में "एकल तर्क inserterपुनरावृत्ति" का प्रस्ताव था । https://isocpp.org/files/papers/p0471r0.html । मुझे पता नहीं चला कि क्या यह प्रस्ताव उन्नत है। मुझे लगता है कि यह समझ में आता है।

अब आपके लिए निर्माता के कार्य को परिभाषित करने वाला यह व्यवहार हो सकता है:

template<class Container>
auto sinserter(Container& c){
    using std::end;
    return std::inserter(c, end(c));
}

इसके समान इस्तेमाल किया:

std::transform(begin(my_vec), end(my_vec), sinserter(my_set), [](auto& e){return e.member;});

क्या यह सभी मानक कंटेनरों पर काम करने का इरादा है? यह std पर काम नहीं करता है :: फॉरवर्ड_लिस्ट (कंपाइलर त्रुटि है "फॉरवर्ड_लिस्ट में 'इन्सर्ट' नाम का कोई सदस्य नहीं है, इंस्टेंटेशन के अंदर insert_iterator::operator=)। इसे होना चाहिए?
डॉन हैच

@ डोनचैच, जो कुछ भी insert(और end) है। ऐसा लगता है कि पहली बार में केवल forward_listएक insertऑपरेशन नहीं है insert_after। और यहां तक ​​कि अगर इसे बदल दिया जाता है तो इसे अंत के बाद नहीं डाला जा सकता है, मुझे लगता है। क्या आप std::listइसके बजाय उपयोग नहीं कर सकते ?
alfC

निश्चित रूप से, मुझे व्यक्तिगत रूप से std :: Forward_list की कोई आवश्यकता नहीं है। लेकिन मुझे एक जेनेरिक में दिलचस्पी है "मैं एक कंटेनर को दूसरे में कैसे कॉपी करूं?" कंटेनर के सभी जोड़े के लिए जिसके लिए यह समझ में आता है। मेरी वर्तमान दिलचस्पी @HowardHinnant के short_alloc जैसे जेनेरिक कंटेनर एलोकेशन एक्सरसाइज के लिए है।
डॉन हैच

@ डोनचैच, बात यह है कि उस प्रश्न के कई प्रकार हैं। ("" मैं एक कंटेनर को दूसरे में कैसे कॉपी करूं? ")। उदाहरण के लिए, क्या आप मूल मूल्यों को संरक्षित करना चाहते हैं, क्या आप आवंटन को कम करना चाहते हैं, आदि सरलतम मामले के लिए मेरी राय में सबसे अच्छा जवाब का उपयोग करना है। कंटेनर जो दो NewContaner new_container(old_other_container.begin(), old_other_container.end())
पुनरावृत्तियों

1
हां, std :: set एक SequentialContainer नहीं है, और यह ठीक है :-) existing_list = std::list(c.begin(), c.end(), existing_list.get_allocator()) बहुत अच्छा, मुझे लगता है कि यह मेरा जवाब है। चीयर्स!
डॉन हैच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.