C ++, वेक्टर पर सेट कॉपी


146

मुझे इसकी प्रतिलिपि बनाने की आवश्यकता std::setहै std::vector:

std::set <double> input;
input.insert(5);
input.insert(6);

std::vector <double> output;
std::copy(input.begin(), input.end(), output.begin()); //Error: Vector iterator not dereferencable

समस्या कहाँ हे?


5
assign()समारोह भी है:output.assign(input.begin(), input.end());
जीन बुशुइव

आपका वेक्टर खाली है। उपाय करने के लिए कई तरीके हैं जो हालांकि लोगों को नीचे इंगित कर रहे हैं।
AJG85 20

@Gene: असाइन () समय से पहले भंडारण की आवश्यक राशि आरक्षित करना चाहता है। यह इनपुट पुनरावृत्तियों का उपयोग यह निर्धारित करने के लिए करेगा कि कितना आवश्यक है, जब तक कि पुनरावृत्तियाँ इनपुटइंटरेटर कड़ाई से नहीं होती हैं, इस स्थिति में यह जमाव को छोड़ देगा और इसके परिणामस्वरूप प्रत्येक पुश_बैक () पर वास्तविक परिणाम प्राप्त होंगे। स्पेक्ट्रम के विपरीत छोर पर, BiderectionalIterators इसे केवल अंत-घटाना शुरू करने की अनुमति देगा। std :: set के पुनरावर्ती, हालांकि, न तो (वे फॉरवर्डइंटरेटर हैं), और यह दुर्भाग्यपूर्ण है: इस मामले में, असाइन () बड़े आकार पर खराब प्रदर्शन - इसके आकार को निर्धारित करने के लिए पूरे सेट पर चलेंगे।
सर्गेई शेवचेंको

जवाबों:


213

आपको उपयोग करने की आवश्यकता है back_inserter:

std::copy(input.begin(), input.end(), std::back_inserter(output));

std::copyउस कंटेनर में तत्वों को नहीं जोड़ा जाता है जिसमें आप सम्मिलित कर रहे हैं: यह नहीं हो सकता; यह केवल कंटेनर में एक पुनरावृत्ति है। इस वजह से, यदि आप सीधे आउटपुट इट्रर पास करते हैंstd::copy यह सुनिश्चित करना चाहिए कि यह उस बिंदु की ओर इशारा करे जो इनपुट रेंज को धारण करने के लिए कम से कम बड़ा हो।

std::back_inserterएक आउटपुट इट्रेटर बनाता है जो push_backप्रत्येक तत्व के लिए कंटेनर पर कॉल करता है, इसलिए प्रत्येक तत्व कंटेनर में डाला जाता है। वैकल्पिक रूप से, आप std::vectorरेंज की प्रतिलिपि बनाने के लिए पर्याप्त संख्या में तत्व बना सकते थे :

std::vector<double> output(input.size());
std::copy(input.begin(), input.end(), output.begin());

या, आप std::vectorरेंज कंस्ट्रक्टर का उपयोग कर सकते हैं :

std::vector<double> output(input.begin(), input.end()); 

3
हाय जेम्स, अपने std के बजाय :: कॉपी लाइन (आपके जवाब में पहला कोड ब्लॉक), क्या मैं output.insert(output.end(), input.begin(), input.end());इसके बजाय नहीं कर सकता था?
user2015453

या सिर्फ cbegin और cend संस्करण का उपयोग करें: आपको output.insert(output.cend(), input.cbegin(), input.cend());क्या लगता है? धन्यवाद।
user2015453

2
क्या मुझे आउटपुट करना चाहिए। इनपुट (input.size ()); अपने आप से या मुझे उम्मीद है कि कुछ संकलक यह मेरे लिए करता है?
जिमीफिकी

@ जिमीफिकी, कोई उम्मीद नहीं कि मुझे डर है।
एलेक्सिस विलके

आपका पहला वेक्टर आरंभीकरण गलत है। आप input,size()खाली प्रविष्टियों की एक सरणी बनाते हैं और फिर उसके बाद एपेंड करते हैं। मुझे लगता है कि आप उपयोग करने का मतलब है std::vector<double> output; output.reserve(input.size()); std::copy(...);
एलेक्सिस विलके

121

वेक्टर के लिए कंस्ट्रक्टर का उपयोग करें जो पुनरावृत्तियों को लेता है:

std::set<T> s;

//...

std::vector v( s.begin(), s.end() );

मान लें कि आप केवल v की s की सामग्री चाहते हैं, और डेटा को कॉपी करने से पहले v में कुछ भी नहीं है।


42

यहाँ एक और विकल्प का उपयोग कर रहा है vector::assign:

theVector.assign(theSet.begin(), theSet.end());

24

आपने अपने सेट की सामग्री को रखने के लिए अपने वेक्टर ऑब्जेक्ट में पर्याप्त स्थान आरक्षित नहीं किया है।

std::vector<double> output(input.size());
std::copy(input.begin(), input.end(), output.begin());

1
यह -1 के लायक नहीं है। विशेष रूप से, यह वेक्टर को केवल एक आवंटन करने की अनुमति देता है (क्योंकि यह ओ (1) में सेट पुनरावृत्तियों की दूरी निर्धारित नहीं कर सकता है), और, अगर यह वेक्टर के लिए परिभाषित नहीं किया गया था जब प्रत्येक तत्व का निर्माण किया गया था, यह हो सकता है एक यादगार के लिए कॉपी को उबालने की अनुमति देने के लिए सार्थक हो। उत्तरार्द्ध अभी भी सार्थक हो सकता है अगर कार्यान्वयन के आंकड़े वेक्टर के कॉटर में लूप को हटा सकते हैं। बेशक, पूर्व को आरक्षित के साथ भी प्राप्त किया जा सकता है।
फ्रेड नर्क

मुझे नहीं पता। मुझे इसमें आपकी मदद करने दीजिए।
विल्हेल्मटेल

मैंने आपको -1 दिया, लेकिन यह मेरी ओर से एक विचार था। एक छोटा संपादन करें ताकि मैं अपने वोट को पूर्ववत कर सकूं, और मैं आपको +1 दूंगा: यह वास्तव में असफल-प्रथम संपत्ति के कारण एक बहुत ही स्वच्छ समाधान है।
फ्रेड फू

मुझे केवल यह पता चला है कि यदि मैं स्वयं उत्तर को संपादित करता हूं, तो मैं एक उत्थान कर सकता हूं। ऐसा करने पर, आपको विफल-प्रथम मेमोरी आवंटन के लिए +1 दिया गया। माफ़ करना!
फ्रेड फू

3

मुझे लगता है कि सबसे कुशल तरीका प्रचार करना और फिर तत्वों का अनुकरण करना है:

template <typename T>
std::vector<T> VectorFromSet(const std::set<T>& from)
{
    std::vector<T> to;
    to.reserve(from.size());

    for (auto const& value : from)
        to.emplace_back(value);

    return to;
}

इस तरह से हम केवल हर तत्व के लिए कॉपी कंस्ट्रक्टर को आमंत्रित करेंगे क्योंकि पहले डिफ़ॉल्ट कंस्ट्रक्टर को कॉल करने का विरोध किया गया था और फिर ऊपर सूचीबद्ध अन्य समाधानों के लिए असाइनमेंट ऑपरेटर की प्रतिलिपि बनाई गई थी। नीचे और अधिक स्पष्टीकरण।

  1. back_inserter का उपयोग किया जा सकता है, लेकिन यह वेक्टर ( https://en.cppreference.com/w/cpp/iterator/back_insert_iterator ) पर push_back () लागू करेगा । emplace_back () अधिक कुशल है क्योंकि यह push_back () का उपयोग करते समय एक अस्थायी बनाने से बचता है । यह तुच्छ रूप से निर्मित प्रकारों के साथ कोई समस्या नहीं है, लेकिन गैर-तुच्छ रूप से निर्मित प्रकारों (जैसे std :: string) के लिए एक प्रदर्शन निहितार्थ होगा।

  2. हमें आकार तर्क के साथ एक वेक्टर के निर्माण से बचने की आवश्यकता है जो सभी तत्वों को डिफ़ॉल्ट रूप से निर्मित करता है (कुछ भी नहीं)। उदाहरण के लिए, std :: copy () का उपयोग करके समाधान के साथ ।

  3. और, अंत में, वेक्टर :: असाइन () विधि या कंस्ट्रक्टर को पुनरावृत्ति रेंज लेने के लिए अच्छे विकल्प नहीं हैं क्योंकि वे सेट पुनरावृत्तियों पर एसटीडी :: दूरी () (तत्वों की संख्या जानने के लिए) को लागू करेंगे । यह सभी सेट तत्वों के माध्यम से अवांछित अतिरिक्त पुनरावृत्ति का कारण होगा क्योंकि सेट बाइनरी सर्च ट्री डेटा संरचना है और यह यादृच्छिक अभिगम पुनरावृत्तियों को लागू नहीं करता है।

उम्मीद है की वो मदद करदे।


कृपया एक प्राधिकरण का संदर्भ जोड़ें कि यह क्यों तेज है और कुछ ऐसा क्यों back_inserterहै जिसका उपयोग करने की आवश्यकता नहीं है
तरिक वेलिंग

उत्तर में और स्पष्टीकरण जोड़े गए।
dshvets1

1

std::copyएक खाली कंटेनर में डालने के लिए इस्तेमाल नहीं किया जा सकता। ऐसा करने के लिए, आपको आवेषण_कारक का उपयोग करने की आवश्यकता है:

std::set<double> input;
input.insert(5);
input.insert(6);

std::vector<double> output;
std::copy(input.begin(), input.end(), inserter(output, output.begin())); 

3
यह पहली बार विफल हो जाता है जब वेक्टर पुन: प्राप्त होता है: आउटपुट से iterator .begin () अमान्य हो जाता है।
फ्रेड नर्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.