인덱스로 std :: vector <>에서 요소를 지우려면 어떻게합니까?


508

std :: vector <int>가 있고 n 번째 요소를 삭제하고 싶습니다. 어떻게합니까?

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

vec.erase(???);

4
양쪽 끝에 삽입 및 삭제를 제공하는 std :: deque를 사용하십시오.
Dario

40
아니요, 요소를 삭제하고 싶을 때만 deque를 사용하지 마십시오. deque 또는 vector를 사용하는 데는 많은 이유가 있습니다. 벡터에서 요소를 삭제하면 비용이 많이들 수 있습니다. 벡터가 크면 esp가 방금 게시 한 코드 예제의 벡터보다 deque가 더 낫다고 생각할 이유가 없습니다.
Owl

6
예를 들어, 대화식으로 항목을 삽입 / 제거하는 항목의 "목록"을 표시하는 그래픽 응용 프로그램이있는 경우 목록을 초당 50-100 회 실행하여 표시하고 몇 가지 항목을 추가 / 제거하는 것을 고려하십시오. 매분마다. 따라서 "목록"을 벡터로 구현하는 것이 전체 효율성 측면에서 더 나은 옵션 일 것입니다.
Michel Billaud 17 년

답변:


705

단일 요소를 삭제하려면 다음을 수행하십시오.

std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

// Deletes the second element (vec[1])
vec.erase(vec.begin() + 1);

또는 한 번에 둘 이상의 요소를 삭제하려면 다음을 수행하십시오.

// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin() + 1, vec.begin() + 3);

50
또한 이진 참고 operator+되어 있지 반드시 같은 다른 컨테이너 유형에 대한 반복자에 대해 정의 list<T>::iterator(당신이 할 수없는 list.begin() + 2std::list, 당신이 사용해야 std::advance하는 경우)
bobobobo

"+1"이 첫 번째 요소 인 myVector [0]이거나 실제 위치 인 myVector [1]
K-SO의 독성이 증가하고 있음을 나타냅니다.

2
미리 반복자를 변수에 저장해야합니다. std :: next를 사용하면 한 줄로 할 수 있습니다. vec.erase (next (bec (, vec), 123));
다니엘

8
답변 한 모든 사람에게 감사합니다. 요소 삭제와 같은 간단한 작업에서 StackOverflow를 사용해야하는 경우 클래스 디자인을 어떻게 생각해야합니까?
Pierre

5
@Pierre 특정 요소 의 숫자 인덱스 가 액세스의 기본 모델이 아니기 때문에 반복자 입니다. 컨테이너의 요소를 보는 모든 함수는 해당 컨테이너의 반복자를 사용합니다. 예std::find_if
Caleth

212

std :: vector의 지우기 메소드가 과부하되어 있으므로 호출하는 것이 더 명확합니다.

vec.erase(vec.begin() + index);

단일 요소 만 지우고 싶을 때


3
그러나 요소 수에 관계없이이 문제가 나타납니다.
Zyx 2000 년

15
요소가 하나만 있으면 index는 0이므로 vec.begin()유효한 요소를 얻습니다 .
앤 퀸

28
누군가는 vec.erase(0)작동하지 않지만 vec.erase(vec.begin()+0)(또는 +0없이) 언급 하지 않았기를 바랍니다 . 그렇지 않으면 내가 여기 온 이유입니다, 일치 함수 호출을 얻을
qrtLs

@qrtLs vec.erase(0)0널 포인터 상수로 해석 될 경우 실제로 컴파일 될 수 있습니다 .
LF

57
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
    std::vector<T>::iterator it = vec.begin();
    std::advance(it, pos);
    vec.erase(it);
}

2
맥스, 그 기능보다 나은 것 : template <typename T> void remove(std::vector<T>& vec, size_t pos) { vec.erase(vec.begin + pos); }나는 개인적으로 관심을 가지지 않고이 질문이 얻을 수있는 최상의 결과를 돌려주는 것이 더 낫다는 말이 아닙니다.

13
@JoeyvG : a vector<T>::iterator는 랜덤 액세스 반복자이므로, 버전이 양호하고 약간 더 명확 할 수 있습니다. 그러나 컨테이너를 랜덤 액세스 반복자를 지원하지 않는 다른 컨테이너로 변경하면 Max가 게시 한 버전이 제대로 작동합니다
Lily Ballard

2
이것은 다른 컨테이너 형식에도 적용되므로 더 나은 대답입니다. std :: next ()를 사용할 수도 있습니다.
Bim

컨테이너 내부에 의존하지 않기 때문에 훨씬 더 나은 접근 방식입니다.
BartoszKP

std :: advance는 이것이 벡터가 아니라고 생각하는 경우에만 필요합니다. 그러나 여기에서 지정했듯이 operator +는 더 간단하지 않습니까? 이 stackoverflow.com/questions/1668088/ 에 따르면 ... 연산자 +
Neil McGill의

14

erase방법은 두 가지 방식으로 사용됩니다.

  1. 단일 요소 지우기 :

    vector.erase( vector.begin() + 3 ); // Deleting the fourth element
  2. 요소 지우기 범위 :

    vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element

7
이것은 수락 된 답변 후 거의 7 년이 지난 중복 답변입니다. 이러지 마십시오.
AlastairG

10

실제로이 erase기능은 두 가지 프로파일에서 작동합니다.

  • 단일 요소 제거

    iterator erase (iterator position);
  • 다양한 요소 제거

    iterator erase (iterator first, iterator last);

std :: vec.begin ()은 컨테이너의 시작을 표시하고 벡터에서 ith 요소를 삭제하려면 다음을 사용할 수 있습니다.

vec.erase(vec.begin() + index);

자세히 살펴보면 vec.begin ()은 벡터의 시작 위치에 대한 포인터 일 뿐이며 i 값을 추가하면 i 위치에 대한 포인터가 증가하므로 대신 i 번째 요소에 대한 포인터에 액세스 할 수 있습니다.

&vec[i]

그래서 우리는 쓸 수 있습니다 :

vec.erase(&vec[i]); // To delete the ith element

6
-1 마지막 행이 컴파일되지 않습니다 (적어도 VS2017에서). 이 코드는 vector :: iterator가 기본적으로 필요하지 않은 원시 포인터에서 암시 적으로 구성 가능하다고 가정합니다.
CuriousGeorge

1
특히 디버그 반복자 마찬가지입니다
Nishant 싱

9

정렬되지 않은 벡터가있는 경우 정렬되지 않은 벡터를 활용하여 CPPCON의 Dan Higgins에서 본 것을 사용할 수 있습니다.

template< typename TContainer >
static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
{
    if ( inIndex < inContainer.size() )
    {
        if ( inIndex != inContainer.size() - 1 )
            inContainer[inIndex] = inContainer.back();
        inContainer.pop_back();
        return true;
    }
    return false;
}

목록 순서는 중요하지 않으므로 목록의 마지막 요소를 가져 와서 제거하려는 항목의 맨 위에 복사 한 다음 마지막 항목을 팝업하여 삭제하십시오.


벡터가 정렬되지 않은 경우 이것이 가장 좋은 대답이라고 생각합니다. iterator + index해당 인덱스에서 반복자 위치를 실제로 돌려주는 가정에 의존하지 않으며 모든 반복 가능한 컨테이너에 해당되는 것은 아닙니다. 백 포인터를 이용하면 선형 대신 복잡성이 일정합니다.
theferrit32

1
이것은 완전히 같은 표준 lib 디렉토리에 추가해야 unordered_remove하고 unordered_remove_if이되었습니다 내가하는이 일 :) 종종 더 많은 일이 일어나고, 그것을 놓친하지 않는 한 ...
윌 크로포드

사본 할당 대신 이동 할당 또는 스왑을 사용하는 것이 좋습니다.
Carsten S

std::remove제거 할 모든 요소가 끝날 수 있도록 컨테이너를 재정렬합니다. C ++ 17을 사용하는 경우 이와 같이 수동으로 수행 할 필요가 없습니다.
keith

@keith 어떻게 std::remove도움이 되나요? cppreference는 C ++ 17에서도 모든 remove오버로드에 술어가 필요하고 인덱스를 취하지 않는다고 주장합니다.
Paul Du Bois

4

큰 벡터 (크기> 100,000)로 작업하고 많은 요소를 삭제하려면 다음과 같이하십시오.

int main(int argc, char** argv) {

    vector <int> vec;
    vector <int> vec2;

    for (int i = 0; i < 20000000; i++){
        vec.push_back(i);}

    for (int i = 0; i < vec.size(); i++)
    {
        if(vec.at(i) %3 != 0)
            vec2.push_back(i);
    }

    vec = vec2;
    cout << vec.size() << endl;
}

이 코드는 vec의 모든 숫자를 3으로 나눌 수 없으며 vec2에 복사합니다. 그런 다음 vec2를 vec로 복사합니다. 꽤 빠릅니다. 20,000,000 개의 요소를 처리하는 데이 알고리즘은 0.8 초만 걸립니다!

나는 지우기 방법으로 똑같은 일을했으며 많은 시간이 걸립니다.

Erase-Version (10k elements)  : 0.04 sec
Erase-Version (100k elements) : 0.6  sec
Erase-Version (1000k elements): 56   sec
Erase-Version (10000k elements): ...still calculating (>30 min)

6
이 질문에 어떻게 대답합니까?
Regis Portalez

4
흥미롭지 만 질문과 관련이 없습니다!
Roddy

인플레 이스 알고리즘이 더 빠르지 않습니까?
user202729

2
의 성병 것을 :: remove_if (+ 삭제)
리야드


3

나는 그것이 당신이 찾고있는 것이라고 믿기 때문에 이것을 읽는 것이 좋습니다. https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom

예를 들어 사용한다면

 vec.erase(vec.begin() + 1, vec.begin() + 3);

벡터의 n 번째 요소를 지우지 만 두 번째 요소를 지우면 벡터의 다른 모든 요소가 이동하고 벡터 크기는 -1이됩니다. 벡터 크기 ()가 줄어들 기 때문에 벡터를 반복하면 문제가 될 수 있습니다. 이와 같은 문제가 발생하면 표준 C ++ 라이브러리에서 기존 알고리즘을 사용하는 것이 좋습니다. "remove"또는 "remove_if".

이것이 도움이 되었기를 바랍니다


0

이전 답변에서는 항상 서명 된 인덱스가 있다고 가정합니다 . 슬프게도, std::vector용도는 size_type색인에 대한, 그리고 difference_type당신이 "-Wconversion"이 친구가 활성화 된 경우, 반복자 산술 그들은 함께 작동하지 않도록. 이것은 서명 된 것과 서명되지 않은 것을 모두 처리 할 수 ​​있고 질문에 대답하는 또 다른 방법입니다.

제거:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
void remove(std::vector<T> &v, I index)
{
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
    v.erase(iter);
}

가지다:

template<class T, class I, class = typename std::enable_if<std::is_integral<I>::value>::type>
T take(std::vector<T> &v, I index)
{
    const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);

    auto val = *iter;
    v.erase(iter);

    return val;
}

0

벡터의 값으로 이것을 찾아서 요소를 삭제하려면 벡터 에서이 작업을 수행하면됩니다.

vector<int> ar(n);
ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));

여기에서 당신의 가치를 제거 할 것입니다. 감사


0

이건 어때요?

void squeeze(vector<int> &v)
{
    int j = 0;
    for (int i = 1; i < v.size(); i++)
        if (v[i] != v[j] && ++j != i)
            v[j] = v[i];
    v.resize(j + 1);
}

-4

가장 빠른 방법 (시간 복잡성으로 컨테스트를 프로그래밍하는 경우 () = 상수)

1 초 안에 100M 항목을 지울 수 있습니다.

    vector<int> it = (vector<int>::iterator) &vec[pos];
    vec.erase(it);

가장 읽기 쉬운 방법 : vec.erase(vec.begin() + pos);


2
이것은 매우 이식성이 없습니다. libstdc ++에서는 작동하지만 libc ++에서는 작동하지 않으며 MSVC에서는 작동하지 않습니다. vector<int>::iterator로 반드시 동일하지 않습니다int *
마샬 Clow

2
역겨워, libstdc ++가 작동하지 않도록 변경 할 것이라고 생각합니다.
Jonathan Wakely 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.