----------------
title : C++ 레퍼런스 - remove 와 remove_if 함수 (<algorithm>)
cat_title : remove, remove_if
ref_title : remove, std::remove, remove_if, std::remove_if
path : /C++ Reference/algorithm
publish_date : 2019-02-18
----------------

##@ cpp-ref-start

#@ remove, remove_if

`<algorithm>` 에 정의됨

```cpp-formatted
template <class ForwardIterator, class T>
ForwardIterator remove(ForwardIterator first, ForwardIterator last,
                       const T& val);

template< class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p );
```

범위 내에 특정 값을 가진 원소들을 제거한다.

범위 (`first` 부터 `last` 전 까지) 내에 원소들 중에서 `val` 과 값이 일치하는 원소(`remove`)들 혹은 조건 `p` 를 만족하는 원소(`remove_if`)를 제거한 범위로 변환합니다. 이 때 이 함수는 해당 범위의 맨 끝을 가리키는 반복자를 리턴합니다.

참고로 이 함수는 실제로 원소를 제거하는 것이 아닙니다. 다만, 지워야 하는 원소들을 컨테이너 맨 뒤로 보내버릴 뿐입니다. 

즉, 위 함수가 리턴하는 반복자 부터 `last` 까지 원소들이 바로 `val` 과 일치하는 원소들로 대체됩니다. 따라서, 실제로 조건을 만족하는 원소들을 **지워** 버리기 위해서는 추가적으로 컨테이너들의 `erase` 함수를 호출해야 합니다.

지워지진 않은 원소들의 상대적 위치는 유지됩니다. 하지만, 지워질 원소들의 상대적 위치의 경우 유지됨이 보장되지 않습니다.

이 함수는 `operator==` 를 이용해서 원소를 비교합니다.

### 인자들

* `first, last` : 원소의 시작과 끝을 가리키는 반복자들. 이 때 확인하는 범위는 `[first, last)` 로 정의됩니다. 이들은 타입 T 와 비교 가능해야 하며 (`operator==` 로), 이동 가능해야만 합니다.
* `val` : 삭제할 값
* `p` : 원소를 한 개만 가지는 단항 함수로 `p` 의 리턴값은 `bool` 로 변환 가능해야만 합니다. 이 때, `p` 는 원소를 변경하면 안됩니다.

### 리턴값

지워지지 않은 마지막 원소 바로 뒤를 가리키는 반복자를 리턴한다. 즉 `first` 부터 이 함수가 리턴하는 반복자 바로 전 까지 `val` 과 일치하지 않는 원소들이 된다.

### 구현 예시

#### remove

```cpp-formatted
template <class ForwardIt, class T>
ForwardIt remove(ForwardIt first, ForwardIt last, const T& value) {
  first = std::find(first, last, value);
  if (first != last)
    for (ForwardIt i = first; ++i != last;)
      if (!(*i == value)) *first++ = std::move(*i);
  return first;
}
```

#### remove_if

```cpp
template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
    first = std::find_if(first, last, p);
    if (first != last)
        for(ForwardIt i = first; ++i != last; )
            if (!p(*i))
                *first++ = std::move(*i);
    return first;
}
```

### 실행 예제

```cpp-formatted
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>

int main() {
  std::string str1 = "Text with some   spaces";
  // 문자열에서 띄어쓰기를 모두 지운다.
  str1.erase(std::remove(str1.begin(), str1.end(), ' '), str1.end());
  std::cout << str1 << '\n';

  std::string str2 = "Text\n with\tsome \t  whitespaces\n\n";
  // 문자열에서 공백 문자 (띄어쓰기, 개행 문자 등등)를 지운다.
  str2.erase(std::remove_if(str2.begin(), str2.end(),
                            [](unsigned char x) { return std::isspace(x); }),
             str2.end());
  std::cout << str2 << '\n';
}
```

실행 결과

```exec
Textwithsomespaces
Textwithsomewhitespaces
```

### 참고 자료

* `remove_copy` : 특정 값들을 복사한 후 지운다.
* `replace$algorithm` : 특정 범위의 원소들을 치환한다.
* `count` : 특정 값과 일치하는 원소의 개수를 센다.
* `find$algorithm` : 범위 안에 원소들 중 값이 일치하는 원소를 찾는다.