it-swarm.com.de

verwenden Sie std :: fill, um den Vektor mit steigenden Zahlen zu füllen

Ich möchte einen vector<int> mit std::fill füllen, aber anstelle eines Werts sollte der Vektor Zahlen in aufsteigender Reihenfolge enthalten.

Ich habe versucht, dies zu erreichen, indem der dritte Parameter der Funktion um eins iteriert wurde. Dies würde jedoch nur Vektoren ergeben, die mit 1 oder 2 gefüllt sind (abhängig von der Position des ++-Operators).

Beispiel:

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
50
BlackMamba

Verwenden Sie vorzugsweise std::iota wie folgt:

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

Wenn Sie keine c++11-Unterstützung haben (immer noch ein echtes Problem, wo ich arbeite), verwenden Sie std::generate wie folgt:

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.
81
BoBTFish

Sie sollten den std::iota-Algorithmus verwenden:

  std::vector<int> ivec;
  std::iota(ivec.begin(), ivec.end(), 0);

Denn std::fill weist den Elementen im angegebenen Bereich [n1, n2) nur den angegebenen festen Wert zu. Und std::iota füllt den angegebenen Bereich [n1, n2) mit fortlaufend ansteigenden Werten, beginnend mit dem Anfangswert und dann mit ++value. Alternativ können Sie std::generate verwenden.

Vergessen Sie nicht, dass std::iota der C++ 11 STL-Algorithmus ist. Viele moderne Compiler unterstützen es jedoch, z. GCC, Clang und VS2012: http://msdn.Microsoft.com/en-us/library/vstudio/jj651033.aspx

23

Meine erste Wahl (selbst in C++ 11) wäre boost::counting_iterator:

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

oder wenn der Vektor bereits konstruiert wurde:

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

Wenn Sie Boost nicht verwenden können: Entweder std::generate (wie in Anderen Antworten vorgeschlagen), oder implementieren Sie counting_iterator selbst, wenn Sie es an verschiedenen Stellen benötigen. (Mit Boost können Sie Einen transform_iterator eines counting_iterator verwenden, um alle Arten von interessanten Sequenzen zu erstellen. Ohne Boost können Sie eine Menge Von Hand entweder in Form eines Generatorobjekts ausführen Typ für std::generate oder als etwas, das Sie an eine Hand anschließen können geschriebener Iterator.)

9
James Kanze

Wenn Sie keine C++ 11-Funktionen verwenden möchten, können Sie 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;
    }
}

Dieses Programm druckt 0 bis 9.

5
Frerich Raabe

Ich habe die Antworten mit std :: generate gesehen, aber Sie können das auch verbessern, indem Sie statische Variablen innerhalb des Lambda verwenden, anstatt einen Zähler außerhalb der Funktion zu deklarieren oder eine Generatorklasse zu erstellen:

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

Ich finde es etwas prägnanter

3
brainsandwich

das funktioniert auch 

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

Wir können die generate - Funktion verwenden, die in der Header-Datei des Algorithmus vorhanden ist.

Code-Auszug :

#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;
}
2
rashedcs

std :: iota ist auf eine Folge n, n + 1, n + 2, ... begrenzt.

Was aber, wenn Sie ein Array mit einer generischen Sequenz f (0), f (1), f (2) usw. füllen möchten? Oft können wir einen Zustandsverfolgungsgenerator vermeiden. Zum Beispiel,

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

erzeugt die Folge von Quadraten

0 1 4 9 16 25 36

Dieser Trick funktioniert jedoch nicht mit anderen Containern.

Wenn Sie mit C++ 98 nicht weiterkommen, können Sie schreckliche Dinge tun wie:

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

und dann

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

Aber ich würde es nicht empfehlen. :)

2
pururu

In Bezug auf die Leistung sollten Sie den Vektor mit den Funktionen reserve() in Kombination mit Push_back() wie im folgenden Beispiel initialisieren:

const int numberOfElements = 10;

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

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

Alle std::fill, std::generate usw. arbeiten mit dem Bereich des vorhandenen Vektorinhalts, und daher muss der Vektor früher mit einigen Daten gefüllt werden. Auch wenn Sie Folgendes tun: std::vector<int> data(10); erstellt einen Vektor, bei dem alle Elemente auf den Standardwert gesetzt sind (d. H. 0 im Fall von int).

Der obige Code vermeidet, den Vektorinhalt zu initialisieren, bevor er mit den Daten gefüllt wird, die Sie wirklich wollen. Die Leistung dieser Lösung ist bei großen Datenmengen gut sichtbar.

1
no one special

Ich habe eine einfache Templat-Funktion, Sequence(), zum Erzeugen von Zahlenfolgen erstellt. Die Funktionalität folgt der Funktion seq() in R ( link ). Das Schöne an dieser Funktion ist, dass sie verschiedene Zahlenfolgen und -typen generiert.

#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;
}

Verwendungsbeispiel:

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

Der einzige Nachteil ist, dass alle Zahlen vom selben abgeleiteten Typ sein sollten. Mit anderen Worten, für Doppel- oder Gleitkommazahlen sollten Dezimalstellen für alle Eingaben enthalten sein (siehe Abbildung).

Aktualisiert: 14. Juni 2018

0
Adam Erickson

Apropos Boost:

auto ivec = boost::copy_range<std::vector<int>>(boost::irange(5, 10));
0
Mikhail

Ich weiß, das ist eine alte Frage, aber ich spiele gerade mit library , um genau dieses Problem zu lösen. Es erfordert 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, ...
0
Dawid

Wenn Sie wirklich std::fill verwenden möchten und auf C++ 98 beschränkt sind, können Sie Folgendes verwenden

#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;
}
0
King Kokonut