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 루프 외부에서 itend정의 된다는 사실입니다 . 그 이유는 무엇입니까?
기독교 라우

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.