std :: fill을 사용하여 증가하는 숫자로 벡터 채우기


82

vector<int>using 을 채우고 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 라이브러리에 이러한 기능이 있지만 벡터 ( boost.org/doc/libs/1_50_0/libs/range/doc/html/range/reference/… )는 허용하지 않지만 일부 사용자 지정 유형은 허용합니다. 다른 옵션이 없나요?
— BlackMamba

2
user1612880, C ++ 11 / Boost를 사용할 수 없다면 Liran의 코드를 사용하십시오. 그것은 아니다 요구 사항 모든 작업이 하나의 줄에 있어야한다 아니다 :-) C 소스 코드 파일에 사용 가능한 문자의 세계적인 부족이 있음
— paxdiablo

부족한 것이 아니라 성능 때문이었습니다. 그러나 잔인한 해킹없이 이것을 가능하게 할 방법이 없다면 Liran이 제공하는 솔루션을 사용할 것입니다.
— BlackMamba

@ user1612880 std::vector. 부스트 버전은 함수 템플릿이며 첫 번째 인수의 "유형 이름"은 개념을 지정합니다. 매우 형식적인 사양 만 찾을 수 있고 간단한 설명이 없기 때문에 말하기는 어렵지만 std::vector개념에 부합 한다고 생각합니다 .
— 제임스 간제

답변:


125

다음 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.)
— 누가 복음 Usherwood

9
그것은 어떤 것을 의미하는 것이 아니라 문자 i에 상응하는 그리스어입니다. APL 의 유사한 기능에 사용되는 이름 이며 Stepanov의 STL에서 많은 아이디어를 촉발시킨 배열 언어입니다.
— BoBTFish 2017

1
아하 고마워! 좋습니다. 이것은 이니셜이 아니라 단어입니다. 나는 지금 그것을 기억하는 것이 더 좋을 것입니다. CPP Reference는 "Increments Of The Start Value"(약간의 유사성에 주목)에 대해 이야기했기 때문에 머리에 이니셜을 넣었습니다. (그리고 그리스어 연결은 인터넷 검색에 의해 즉각적으로 명확하지 않습니다.) 역사적인 참고 자료도 감사합니다.
— Luke Usherwood

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를 나타냅니다. 나는 원래 APL 에서이 이상한 이름이 “integer”(수학에서는 복소수의 허수 부분을 나타내는 데 널리 사용되지만) 유사하기 때문에 선택되었다고 추측합니다 .


1
당신은 표준을 추가 할 수 있습니다 : 이오타 (11) C ++에서입니다
— hetepeperfan

@AlexanderKaraberov 그러나 대부분의 장소는 최신 버전의 컴파일러를 사용하지 않으며 C ++ 11을 사용할 수 없습니다.
— 제임스 간제

1
iota어떤 컴파일러는 항상 긴 C ++ 11 전에, 그것을 지원했다, 그래서 15 년 이상 전에 STL에 있었다
— 조나단 Wakely

2
이 벡터의 크기는 0입니다. 컨테이너에 크기를 추가해야합니다. std :: vector <int> ivec (100); std :: iota (ivec.begin (), ivec.end (), 0);
— AKludges

13

내 첫 번째 선택 (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() );

Boost를 사용할 수 없다면 std::generate(다른 답변에서 제안한대로) 또는 counting_iterator필요한 경우 다양한 장소에서 직접 구현 하십시오. (Boost를 사용하면 transform_iterator의 a counting_iterator를 사용하여 모든 종류의 흥미로운 시퀀스를 만들 수 있습니다 . Boost 없이는에 대한 생성기 객체 유형의 형태로 std::generate또는에 연결할 수있는 방식으로이 작업을 직접 수행 할 수 있습니다. 손으로 쓴 계산 반복자.)


코드의 첫 번째 부분에서는 생성자 의 std::vectorIS 호출되고? 범위 생성자 여야 하지만 boost::counting_iterator암시 적으로 InputIterator 로 변환 할 수 있습니까?
— CinCout

8

std :: generate로 답을 봤지만 함수 외부에서 카운터를 선언하거나 생성기 클래스를 만드는 대신 람다 내부에서 정적 변수를 사용하여 "개선"할 수도 있습니다.

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

좀 더 간결하다고 생각합니다


5
static여기에 잘못된 의미가 있습니다. IMO. 일반화 된 캡처를 사용 [i = 0]() mutable하여 변수가 생성 된 클래스 유형이 아닌 람다의 특정 인스턴스로 범위가 지정됨을 명확히합니다. 실제로 차이가있을 수있는 상황을 해석하는 것은 어렵고 의심스러운 디자인을 나타낼 수 있지만 어쨌든 멤버 변수를 사용하면 의미론이 더 우수하다고 생각합니다. 또한 더 간결한 코드를 만듭니다. 이제 람다의 본문은 단일 문이 될 수 있습니다.
— underscore_d

예, 더 좋아 보입니다. 나는 :) 전에 람다 캡처에서 초기화 변수 본 적이
— brainsandwich

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
매우 직관적이지 않고 간소화되지 않은 것은 for 루프 외부에서 it및 end정의 된다는 사실입니다 . 그 이유는 무엇입니까?
— 기독교 라우

1
두 번째 이유는 (예 : 바보 VS 버그는하지만, 그것은 프로젝트 설정에 변하기 쉬워의 모든에서 합리적인 수까지) 합리적인 소리 @FrerichRaabe,하지만 난 뭐가 잘못 첫 번째 이유,하지 않습니다 std::vector<int>::const_iterator it = vec.begin(), end = ivec.end()(어느 쪽도 반복하지 타이핑도 반복 호출)? 그리고 줄이 길어지면 C ++이고 어차피 가끔 줄 바꿈을하지 않을 것입니다 (그리고 좋은 80 자 디스플레이의 시대는 끝났습니다). 하지만 그것은 맛의 문제라고 생각하고 당신은 어쨌든 오래 전에 내 찬성표를 얻었습니다.
— 기독교 라우

2
@ChristianRau : 솔직히 말해서 저는 편집중인 파일의 코드가 사용하는 스타일을 사용합니다. 즉, 지금까지 언급 한 장단점 또는 단점보다 일관성을 중요하게 생각합니다.
— Frerich Raabe 2013

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

이것은 매우 우아한 대답이며 아마도 일반적인 경우 가장 간결 할 것입니다.
— Owl

1
IMO는 n일반화 된 캡처를 통해 람다의 구성원 을 만드는 것이 우수 [n = 0]() mutable하므로 주변 범위를 오염시키지 않습니다.
— underscore_d

저는 이것을 사용하고 있습니다. 고급 상황에는 유용하지 않을 수 있지만 C ++ 초보자에게는 충분합니다. 람다를 사용할 수 있다면 좋은 해결책입니다.
— Abinash Dash

4

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
OP는 C ++ 11 (람바 없음)을 사용할 수 없음
— yizzlez 2014 년

2

이것은 또한 작동합니다

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

2
물론 반복자를 수동으로 살펴보면 작동하지만 OP가 그렇게하고 싶다면 stdlib 알고리즘에 대해 묻지 않았을까요?
— underscore_d

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

iota를 사용하지 않는 또 다른 옵션이 있습니다. 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. Lambda는 외부 범위 [&]를 캡처하므로 표현식 내에서 사용할 수 있습니다.
  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

부스트에 대해 말하면 :

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

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
Yikes. 이는 코드를 읽기가 매우 어렵고,로 시작하는 식별자 _가 구현에 예약되어 있기 때문에 작성된 전역 범위에서도 유효하지 않습니다 .
— underscore_d

0

Sequence()일련의 숫자를 생성하기 위해 간단한 템플릿 함수를 만들었습니다 . seq()기능은 R ( 링크 ) 의 기능을 따릅니다 . 이 함수의 좋은 점은 다양한 숫자 시퀀스와 유형을 생성하는 데 작동한다는 것입니다.

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

유일한주의 사항은 모든 숫자가 동일한 유추 유형이어야한다는 것입니다. 즉, double 또는 float의 경우 표시된대로 모든 입력에 대해 소수를 포함합니다.

업데이트 날짜 : 2018 년 6 월 14 일


0

brainsandwich와 underscore_d는 아주 좋은 아이디어를주었습니다. 채우기는 내용을 변경하는 것이므로 STL 알고리즘 중 가장 간단한 for_each ()도 청구서를 채워야합니다.

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에서 숫자 모드는 실제로 두 배이므로 유형을 매개 변수화 할 필요가 없습니다. double을 사용하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.