एसटीडी का उपयोग करें: बढ़ती संख्या के साथ वेक्टर को आबाद करने के लिए भरें


85

मैं एक भरना चाहूंगा vector<int> उपयोगstd::fill , लेकिन एक मूल्य के बजाय, वेक्टर को बाद में बढ़ते क्रम में संख्याओं को शामिल करना चाहिए।

मैंने फ़ंक्शन के तीसरे पैरामीटर को एक-एक करके पुनरावृत्त करके इसे प्राप्त करने का प्रयास किया, लेकिन यह मुझे केवल 1 या 2 ( ++ऑपरेटर की स्थिति के आधार पर ) से भरे हुए वैक्टर देगा ।

उदाहरण:

vector<int> ivec;
int i = 0;
std::fill(ivec.begin(), ivec.end(), i++); // elements are set to 1
std::fill(ivec.begin(), ivec.end(), ++i); // elements are set to 2

25
std::iotaइसके बजाय का उपयोग करें std::fill(यह मानते हुए कि आपका संकलक नया है, वैसे भी इसका समर्थन करने के लिए पर्याप्त है)।
जेरी कॉफिन

1
दुर्भाग्य से, यह नए मानक का हिस्सा लगता है (जिसका मुझे उपयोग नहीं करना चाहिए)। मैंने देखा कि BOOST लाइब्रेरी में इस तरह का एक फ़ंक्शन है, लेकिन यह वैक्टर ( बूस्ट डॉट ओआरजी / डॉक / एलिब / 1_50_0/libs/range/doc/html/range/reference/… ) लेकिन कुछ कस्टम प्रकार स्वीकार नहीं करता है । क्या कोई और विकल्प नहीं है?
ब्लैकमबा

2
user1612880, यदि आप C ++ 11 / Boost का उपयोग नहीं कर सकते हैं, तो केवल Liran के कोड का उपयोग करें। यह आवश्यक नहीं है कि हर ऑपरेशन एक ही लाइन पर हो और न ही सी सोर्स कोड फ़ाइलों के लिए उपलब्ध वर्णों की विश्व-व्यापी कमी है :-)
paxdiablo

यह कमी के लिए नहीं बल्कि प्रदर्शन के लिए होगा। हालांकि, अगर क्रूर हैक के बिना इसे संभव बनाने का कोई तरीका नहीं है, तो मैं लिरन द्वारा प्रदान किए गए समाधान का उपयोग करूंगा।
ब्लैकमबा

@ user1612880 उसे अपने साथ करने की कोशिश की है std::vector। बूस्ट संस्करण एक फ़ंक्शन टेम्प्लेट है, और पहले तर्क का "प्रकार नाम" एक अवधारणा को निर्दिष्ट करता है। यह बताना मुश्किल है, क्योंकि मैं केवल एक बहुत ही औपचारिक विनिर्देश, और कोई सरल विवरण नहीं पा सकता हूं, लेकिन मुझे लगता है कि std::vectorयह अवधारणा के अनुरूप है।
जेम्स कंज

जवाबों:


128

अधिमानतः std::iotaइस तरह का उपयोग करें:

std::vector<int> v(100) ; // vector with 100 ints.
std::iota (std::begin(v), std::end(v), 0); // Fill with 0, 1, ..., 99.

उस ने कहा, अगर आपके पास कोई c++11समर्थन नहीं है (फिर भी एक वास्तविक समस्या जहां मैं काम करता हूं), std::generateइस तरह का उपयोग करें:

struct IncGenerator {
    int current_;
    IncGenerator (int start) : current_(start) {}
    int operator() () { return current_++; }
};

// ...

std::vector<int> v(100) ; // vector with 100 ints.
IncGenerator g (0);
std::generate( v.begin(), v.end(), g); // Fill with the result of calling g() repeatedly.

6
पृथ्वी पर iotaवैसे भी क्या खड़ा है? (ऐसा लगता है कि किसी ने समान रूप से स्पष्ट गलत itoa
समझा

9
यह किसी भी चीज़ के लिए "स्टैंड" नहीं करता है, यह अक्षर i का ग्रीक समकक्ष है। यह एपीएल में एक समान फ़ंक्शन के लिए उपयोग किया जाने वाला नाम है , और एरे भाषा है जिसने स्टेपनोव के एसटीएल में कई विचारों को उगल दिया।
BoBTFish

1
आह-हा धन्यवाद! ठीक है तो यह एक शब्द है जो एक प्रारंभिकता के बजाय है; मुझे शायद अब यह याद रखना बेहतर होगा। सीपीपी संदर्भ ने "प्रारंभिक मूल्य में वृद्धि" के बारे में बात की थी (थोड़ी समानता पर ध्यान दें) इसलिए मुझे अपने सिर में शुरुआती मिला। (और Googling द्वारा ग्रीक कनेक्शन तुरंत स्पष्ट नहीं है।) ऐतिहासिक संदर्भ के लिए भी धन्यवाद।
ल्यूक उशरवुड

47

आपको std::iotaएल्गोरिथ्म (परिभाषित <numeric>) का उपयोग करना चाहिए :

  std::vector<int> ivec(100);
  std::iota(ivec.begin(), ivec.end(), 0); // ivec will become: [0..99]

क्योंकि std::fillबस दिए गए रेंज में तत्वों को दिए गए निश्चित मान को निर्दिष्ट करता है [n1,n2)। और std::iotaदिए गए रेंज [n1, n2)को क्रमिक रूप से बढ़ते मूल्यों से भरता है , प्रारंभिक मूल्य के साथ शुरू होता है और फिर उपयोग करता है ++value। आप भी उपयोग कर सकते हैंstd::generate एक विकल्प के रूप में ।

मत भूलना कि std::iotaC ++ 11 STL एल्गोरिथ्म है। लेकिन बहुत सारे आधुनिक संकलक इसका समर्थन करते हैं जैसे GCC, Clang और VS2012: http://msdn.microsoft.com/en-us/library/vstudio/jj651033.aspx

PS यह फ़ंक्शन प्रोग्रामिंग भाषा APL से पूर्णांक फ़ंक्शन के नाम पर है , और एक ग्रीक पत्र iota का प्रतीक है। मैं अनुमान लगाता हूं कि मूल रूप से एपीएल में यह विषम नाम चुना गया था क्योंकि यह एक जैसा दिखता है “integer”(भले ही गणित में कोटा का उपयोग किसी जटिल संख्या के काल्पनिक भाग को दर्शाने के लिए किया जाता है)।


1
आप std जोड़ना चाह सकते हैं :: iota C ++ 11 से है
hetepeperfan

@AlexanderKaraberov लेकिन अधिकांश स्थान संकलक के नवीनतम संस्करण का उपयोग नहीं कर रहे हैं, और C ++ 11 का उपयोग नहीं कर सकते हैं।
जेम्स कंज

1
iotaएसटीएल में 15 साल से अधिक समय से था, इसलिए कुछ संकलक ने हमेशा इसका समर्थन किया है, सी ++ 11 से बहुत पहले
जोनाथन वेकली

2
उस वेक्टर का एक आकार होगा 0. आपको कंटेनर में एक आकार जोड़ना होगा: std :: वेक्टर <int> ivec (100); std :: iota (ivec.begin (), ivec.end (), 0);
एके

14

मेरी पहली पसंद (C ++ 11 में भी) होगी boost::counting_iterator:

std::vector<int> ivec( boost::counting_iterator<int>( 0 ),
                       boost::counting_iterator<int>( n ) );

या यदि वेक्टर पहले से ही निर्मित था:

std::copy( boost::counting_iterator<int>( 0 ),
           boost::counting_iterator<int>( ivec.size() ),
           ivec.begin() );

यदि आप बूस्ट का उपयोग नहीं कर सकते हैं: या तो std::generate(जैसा कि अन्य उत्तरों में सुझाव दिया गया है), या counting_iteratorयदि आप इसे विभिन्न स्थानों में चाहते हैं, तो अपने आप को लागू करें। (बूस्ट के साथ, आप सभी प्रकार के दिलचस्प दृश्यों को बनाने के लिए एक transform_iteratorका उपयोग कर सकते हैं counting_iterator। बूस्ट के बिना, आप इसे हाथ से बहुत कुछ कर सकते हैं, या तो जनरेटर ऑब्जेक्ट के प्रकार के std::generateरूप में, या कुछ के रूप में आप प्लग इन कर सकते हैं। हाथ से लिखी जाने वाली गिनती।


कोड के पहले टुकड़े में, किस निर्माता को std::vectorकहा जा रहा है? रेंज कंस्ट्रक्टर होना चाहिए , लेकिन boost::counting_iteratorएक इनपुटइंटरेटर को स्पष्ट रूप से परिवर्तनीय है ?
सिनेकाउट

8

मैंने स्टैड के साथ उत्तर देखे हैं :: उत्पन्न लेकिन आप "सुधार" भी कर सकते हैं कि फ़ंक्शन के बाहर एक काउंटर घोषित करने या जनरेटर वर्ग बनाने के बजाय, लैम्ब्डा के अंदर स्थिर चर का उपयोग करके:

std::vector<int> vec;
std::generate(vec.begin(), vec.end(), [] {
    static int i = 0;
    return i++;
});

मुझे यह थोड़ा अधिक संक्षिप्त लगता है


5
staticयहाँ गलत शब्दार्थ है, IMO। मैं एक सामान्यीकृत कैप्चर का उपयोग करूंगा [i = 0]() mutableताकि यह स्पष्ट हो जाए कि चर को लैम्ब्डा के विशिष्ट उदाहरण के लिए स्कूप किया गया है, न कि इसके टाइप प्रकार को। ऐसी स्थिति को रोकना मुश्किल है जहां अभ्यास में अंतर होगा, और यह संभवतः एक संदिग्ध डिजाइन का संकेत देगा, लेकिन किसी भी मामले में मुझे लगता है कि सदस्य चर का उपयोग करते हुए शब्दार्थ बेहतर हैं। इसके अलावा, यह अधिक संक्षिप्त कोड के लिए बनाता है; अब मेमने का शरीर एक ही कथन हो सकता है।
अंडरस्कोर_ड

हाँ जो बेहतर लगता है; मैंने इससे पहले
लैंबडा

6

यदि आप C ++ 11 सुविधाओं का उपयोग नहीं करते हैं, तो आप उपयोग कर सकते हैं std::generate:

#include <algorithm>
#include <iostream>
#include <vector>

struct Generator {
    Generator() : m_value( 0 ) { }
    int operator()() { return m_value++; }
    int m_value;
};

int main()
{
    std::vector<int> ivec( 10 );

    std::generate( ivec.begin(), ivec.end(), Generator() );

    std::vector<int>::const_iterator it, end = ivec.end();
    for ( it = ivec.begin(); it != end; ++it ) {
        std::cout << *it << std::endl;
    }
}

यह कार्यक्रम 0 से 9 प्रिंट करता है।


3
@bitmask निश्चित रूप से अगर आपके पास लैम्ब्डा है तो आपके पास std::iotaवैसे भी है, नहीं?
BoBTFish

1
@bitmask लेकिन इसके लिए C ++ 11 :)
juanchopanza

2
क्या काफी अचूक और गैर-सुव्यवस्थित है यह तथ्य है कि itऔर endफॉर-लूप के बाहर परिभाषित किया गया है। इसका कोई कारण?
क्रिश्चियन रौ

1
@FrerichRaabe दूसरा कारण उचित लगता है (जहां तक ​​इस तरह के बेवकूफ वी.एस. बग बिल्कुल उचित हो सकता है, हालांकि, यह परियोजना सेटिंग्स में बदलने योग्य है), लेकिन मुझे पहला कारण नहीं मिलता है, क्या गलत है std::vector<int>::const_iterator it = vec.begin(), end = ivec.end()(न ही दोहराया टाइपिंग न ही बार-बार फोन करना)? और लाइन लंबी, अच्छी तरह से, यह C ++ है और आप किसी भी तरह से कभी-कभार लाइन ब्रेक नहीं लेंगे (और अच्छे पुराने 80-कैरेक्टर डिस्प्ले के दिन खत्म हो चुके हैं)। लेकिन यह मेरे स्वाद की बात है, मुझे लगता है कि आप मेरे उत्थान से बहुत पहले, वैसे भी।
क्रिश्चियन राऊ

2
@ChristianRau: पूरी तरह से ईमानदार होने के लिए: व्यवहार में मैं जिस भी शैली में कोड का उपयोग कर रहा हूं उस फ़ाइल में कोड का उपयोग करता हूं, अर्थात मैं अब तक उल्लिखित किए गए अधिवक्ताओं या नुकसानों की तुलना में अधिक है।
फ्राईच रायबे

6

हम जनरेट का उपयोग कर सकते हैं एल्गोरिथ्म हेडर फ़ाइल में मौजूद फ़ंक्शन ।

सांकेतिक टुकड़ा :

#include<bits/stdc++.h>
using namespace std;


int main()
{
    ios::sync_with_stdio(false);

    vector<int>v(10);

    int n=0;

    generate(v.begin(), v.end(), [&n] { return n++;});

    for(auto item : v)
    {
      cout<<item<<" ";
    }
    cout<<endl;

    return 0;
}

यह एक बहुत ही सुंदर जवाब है और शायद सामान्य मामले में सबसे संक्षिप्त है।
उल्लू

1
IMO nसामान्यीकृत कैप्चर के माध्यम से लैम्ब्डा का सदस्य बनाना बेहतर है [n = 0]() mutable, इसलिए यह आसपास के दायरे को प्रदूषित नहीं करता है।
अंडरस्कोर_ड

मैं इस एक का उपयोग कर रहा हूँ। उन्नत स्थितियों के लिए उपयोगी नहीं हो सकता है लेकिन सी ++ शुरुआती लोगों के लिए पर्याप्त है। अच्छा समाधान अगर एक लैम्ब्डा का उपयोग कर सकते हैं।
अविनाश डैश 21

5

std :: iota एक सीक्वेंस n, n + 1, n + 2, ... तक सीमित है

लेकिन क्या हो अगर आप जेनेरिक सीक्वेंस f (0), f (1), f (2), आदि के साथ एक अरेंजमेंट भरना चाहते हैं? अक्सर, हम एक राज्य ट्रैकिंग जनरेटर से बच सकते हैं। उदाहरण के लिए,

int a[7];
auto f = [](int x) { return x*x; };
transform(a, a+7, a, [a, f](int &x) {return f(&x - a);});

वर्गों के अनुक्रम का उत्पादन करेगा

0 1 4 9 16 25 36

हालांकि, यह ट्रिक अन्य कंटेनरों के साथ काम नहीं करेगी।

यदि आप C ++ 98 के साथ फंस गए हैं, तो आप भयानक काम कर सकते हैं जैसे:

int f(int &x) { int y = (int) (long) &x / sizeof(int); return y*y; }

और फिर

int a[7];
transform((int *) 0, ((int *) 0) + 7, a, f);

लेकिन मैं इसकी सिफारिश नहीं करूंगा। :)


1
ओपी C ++ 11 (कोई लैंबस) का उपयोग नहीं कर सकता
yizzlez


2

यह भी काम करता है

j=0;
for(std::vector<int>::iterator it = myvector.begin() ; it != myvector.end(); ++it){
    *it = j++;
}

2
बेशक, iterators के साथ मैन्युअल रूप से poking, लेकिन अगर ओपी ऐसा करना चाहता था, तो उन्होंने एक stdlib एल्गोरिथ्म के बारे में नहीं पूछा होगा, क्या वे?
अंडरस्कोर_ड

2

प्रदर्शन के संदर्भ में आपको वेक्टर को प्रारंभिक कार्यों reserve()के साथ संयुक्त करना चाहिए push_back()जैसे नीचे दिए गए उदाहरण में:

const int numberOfElements = 10;

std::vector<int> data;
data.reserve(numberOfElements);

for(int i = 0; i < numberOfElements; i++)
    data.push_back(i);

सभी std::fill, std::generateआदि मौजूदा वेक्टर सामग्री की सीमा पर काम कर रहे हैं, और इसलिए वेक्टर कुछ डेटा पहले से भरा जाना चाहिए। यहां तक ​​कि निम्नलिखित करते हुए: std::vector<int> data(10);सभी तत्वों के साथ एक वेक्टर बनाता है जो अपने डिफ़ॉल्ट मान पर सेट होता है (यानी के मामले में 0)int ) पर ।

उपरोक्त कोड आपको वास्तव में इच्छित डेटा के साथ भरने से पहले वेक्टर सामग्री को आरंभ करने से बचता है। इस समाधान का प्रदर्शन बड़े डेटा सेट पर अच्छी तरह से दिखाई देता है।


2

एक और विकल्प है - बिना कोटा का उपयोग किए। For_each + लैम्ब्डा अभिव्यक्ति का उपयोग किया जा सकता है:

vector<int> ivec(10); // the vector of size 10
int i = 0;            // incrementor
for_each(ivec.begin(), ivec.end(), [&](int& item) { ++i; item += i;});

दो महत्वपूर्ण चीजें क्यों काम कर रही हैं:

  1. लैम्ब्डा बाहरी दायरे [और] को पकड़ता है जिसका अर्थ है कि मैं अभिव्यक्ति के अंदर उपलब्ध होगा
  2. आइटम को संदर्भ के रूप में पारित किया गया है, इसलिए, यह वेक्टर के अंदर परिवर्तनशील है

1

अगर तुम सच में में उपयोग करना चाहते हैं std::fillऔर C ++ 98 तक सीमित हैं, तो आप निम्न जैसे कुछ का उपयोग कर सकते हैं,

#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>

struct increasing {
    increasing(int start) : x(start) {}
    operator int () const { return x++; }
    mutable int x;
};

int main(int argc, char* argv[])
{
    using namespace std;

    vector<int> v(10);
    fill(v.begin(), v.end(), increasing(0));
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
    cout << endl;
    return 0;
}

1

मुझे पता है कि यह पुराना सवाल है, लेकिन मैं इस समस्या से निपटने के लिए वर्तमान में लाइब्रेरी के साथ खेल रहा हूं । इसके लिए c ++ 14 की आवश्यकता है।

#include "htl.hpp"

htl::Token _;

std::vector<int> vec = _[0, _, 100];
// or
for (auto const e: _[0, _, 100]) { ... }

// supports also custom steps
// _[0, _%3, 100] == 0, 4, 7, 10, ...

1
ओह। कोड पढ़ना बहुत कठिन है, और यह वैश्विक दायरे में भी अमान्य होगा, जैसा कि लिखा गया है, क्योंकि शुरुआत करने वाले पहचानकर्ता _वहां कार्यान्वयन के लिए आरक्षित हैं।
अंडरस्कोर_ड

0

मैंने Sequence()संख्याओं के अनुक्रम उत्पन्न करने के लिए , एक साधारण टेम्प्लेटेड फ़ंक्शन बनाया । कार्यक्षमता seq()आर ( लिंक ) में फ़ंक्शन का अनुसरण करती है । इस फ़ंक्शन के बारे में अच्छी बात यह है कि यह कई प्रकार के क्रम और प्रकार उत्पन्न करने के लिए काम करता है।

#include <iostream>
#include <vector>

template <typename T>
std::vector<T> Sequence(T min, T max, T by) {
  size_t n_elements = ((max - min) / by) + 1;
  std::vector<T> vec(n_elements);
  min -= by;
  for (size_t i = 0; i < vec.size(); ++i) {
    min += by;
    vec[i] = min;
  }
  return vec;
}

उदाहरण उपयोग:

int main()
{
    auto vec = Sequence(0., 10., 0.5);
    for(auto &v : vec) {
        std::cout << v << std::endl;
    }
}

एकमात्र चेतावनी यह है कि सभी संख्याएं समान अनुमान वाली होनी चाहिए। दूसरे शब्दों में, डबल्स या फ़्लोट्स के लिए, सभी इनपुट के लिए दशमलव शामिल करें, जैसा कि दिखाया गया है।

Updated: 14 जून, 2018


0

brainsandwich और underscore_d ने बहुत अच्छे विचार दिए। चूंकि सामग्री को बदलना है, for_each (), STL एल्गोरिदम में सबसे सरल, बिल भी भरना चाहिए:

std::vector<int> v(10);
std::for_each(v.begin(), v.end(), [i=0] (int& x) mutable {x = i++;});    

सामान्यीकृत कैप्चर [i=o]एक लंबर के साथ लैम्ब्डा अभिव्यक्ति प्रदान करता है और इसे एक ज्ञात स्थिति में शुरू करता है (इस मामले में 0)। कीवर्ड mutableइस स्थिति को अपडेट करने की अनुमति देता है, जब लैम्बडा कहा जाता है।

वर्गों का अनुक्रम प्राप्त करने के लिए केवल एक मामूली संशोधन करना पड़ता है:

std::vector<int> v(10);
std::for_each(v.begin(), v.end(), [i=0] (int& x) mutable {x = i*i; i++;});

R-like seq उत्पन्न करना अधिक कठिन नहीं है, लेकिन ध्यान दें कि R में, संख्यात्मक मोड वास्तव में डबल है, इसलिए वास्तव में टाइप को पैरामीट्रिज करने की आवश्यकता नहीं है। बस डबल का उपयोग करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.