2012-11-02 3 views
3

값이 특정 간격 내에있는 벡터 (또는 다른 stl 컨테이너)에서 항목을 제거하는 편리한 방법이 있습니까?C++ 값이 간격 내에있는 벡터에서 항목을 제거합니다.

그래서 예를 들면 : 나는 부동 소수점과 벡터

1.1 1.3 2.2 3.2 4.1 5.2 5.1 1.1 8.0 2.1 

다음과 같은 결과로 이어질해야 0.2의 델타를, 값 가지고, 따라서 모두가 "복제"항목에서 제거

1.1 2.2 3.2 4.1 5.1 8.0 

델타 값을 범위 내에서 유지하십시오. 값이 "클러스터 됨"이라고 가정 할 수 있습니다. 클러스터의 차이는 3 * 델타 이상입니다. 클러스터의 하나의 값 (평균) 만 유지해야하며 클러스터의 다른 모든 값은 제거해야합니다.

중첩 루프를 반복 할 수는 있지만 iterator가 변경되기 때문에 이것은 매우 복잡해 보입니다. 그래서 나는 더 편리한 방법을 생각했습니다. 예를 들어 remove_if를 찾았지만이 함수는 "비교"할 수 없습니다.

제안 해 주셔서 감사합니다.

+0

맞 내 예에서 그 중간 값이어야하지만, 어쨌든 내삽을 위해 평균을 계산합니다. –

답변

5

당신은 술어 std::unique를 사용할 수 있습니다

template <typename It, typename Predicate> 
It unique(It first, It last, Predicate pred); 

std::unique의 가장 많이 사용되는 형태는 시퀀스에서 중복을 아무 조건도지지 않습니다 그냥 제거합니다. 그러나 필터를 구현하는 필터를 작성할 수 있습니다 (귀하의 경우, 간격을 사용하여 두 값을 비교). 그러면 사용자가 설정됩니다. 같은 뭔가 :

bool CompareWithGap(double a, double b) 
{ 
    return abs(a - b) <= 0.2; 
} 

그리고 std::unique 전화를 사용 v이 벡터 (또는 다른 순서)이다

auto it = std::unique(v.begin(), v.end(), CompareWithGap); 

.

편집 : std::unique을 사용하기 전에 시퀀스를 정렬해야한다는 점을 잊어 버렸습니다. 이것이 옵션이 아니면 자신 만의 알고리즘을 작성해야합니다.

2 편집 : 자신의 의견에 기독교 라우에 의해 지적 완료를 들어, 지금의 erase 방법을 사용하여 시퀀스에서 제거 항목을 지울 수 있습니다 :

v.erase(it, v.end()); 
+1

아마도'std :: vector :: erase'와 쌍을 이룰 것입니다. –

+0

@ChristianRau 참으로 쓸모없는 흔적을 제거합니다. – Gorpik

+0

감사합니다. 이것은 매우 쉬운 접근 방법이며 작동합니다. –

0

기존 벡터를 반복하고 원하는 데이터로 채우는 동안 새 벡터를 만들 수 있습니까? 그런 다음 이전 벡터를 제거하고 새 벡터에 대한 참조를 반환 할 수 있습니다.

+1

이러한 적절한 기능적 접근은 확실히 좋은 생각이지만, "당신은 ... 새 벡터에 대한 참조를 반환 할 수 있습니다."라고 잘못되었습니다. 새로운 객체를 값 (또는 스마트 포인터)으로 반환해야합니다. 아마 결과는 결과를 입력과 교환 한 다음 임시 결과가 범위를 벗어나게하는 것입니다. – leftaroundabout

+0

+1 당신은 내 요점을 가지고 :) –

4

'범위 내의 값 중 하나'가 잘 정의되어 있지 않기 때문에 질문하는 것은 실제로 상당히 복잡합니다. 예를 들면 주어진

1.1 1.2 1.3

계속 하시겠습니까? 아마도 첫 번째, 즉 1.1입니다. OK 이제 어떻게 첫 번째 규칙에 따라 1.3

1.1 0.9

에 대해서는, 0.9 및 1.3 유지, 그러나 우리는 단지 1.1 대신 유지할 수 있었다. 내가 생각하는 질문은 0.9와 1.3의 'duplicates'인가 그렇지 않은가? 나는 당신이 이것을 충분히 정의했다고 생각하지 않는다.

이 경우는 어떻게됩니까? 1.1 1.2 1.3 1.4 1.5 1.6? 모든 값은 하나의 다른 값의 0.2 이내이지만 모든 값이 다른 모든 값의 0.2 이내에있는 것은 아닙니다. 그래서 그들은 모두 중복됩니까? 또는 그들을 분할해야합니까? 그렇다면 어떻게 분할해야할까요? 아마도 1.1과 1.4를 골라야할까요?

여러분이 문제를 좀 더 정확하게 정의 할 때까지 코드를 작성하거나 우리에게 도움을 줄 수는 없습니다.

disjoint-set data structure을 볼 수 있습니다. 정확하게 무엇을하려고하는지에 따라이 문제를 해결하는 가장 효율적인 방법이 될 수 있습니다.

+0

고마워, 내 설명을 편집했습니다. 값이 클러스터되어 있다고 가정 할 수 있으므로 1.1 1.1 1.2 1.3 1.4 1.5 1.6은 나타나지 않아야합니다. 예를 들어 1.1 1.12 1.0 1.13 1.14 2.0 2.1 2.15 2.16 –

+0

글쎄, 분리 된 데이터 구조가 실제로 작동 할 것입니다. 패턴 인식 알고리즘을 사용할 수도 있습니다. mean-shift, 그러나 이것은이 어플리케이션에있어 과잉이다. 나는 간단한 stl 컨테이너 기반 접근 방식을 선호 할 것이다. –

+0

전적으로 동의하지만, 주석의 제한된 공간에 잘 맞지 않더라도 대답보다 더 많은 주석을 사용한다는 것을 명심하십시오. –

0

첫 번째 항목을 유지하는 것이 필요한 경우 (따라서 0.9, 1.1 및 1.3을 사용하는 경우 0.9 및 1.3을 유지) 그러면 술어는 클래스 여야합니다.

이상적 클래스는 다음과 같이 보일 것이다 : std::remove_if에 대한 펑 술어 클래스로 작동해야하지만 내부 표준을 복사 할 수 있습니다

class IsWithinRange 
{ 
    std::set<double> values; 
    double tolerance; 

public: 
    explicit IsWithinRange(double tol) : tolerance(tol) 
    { 
    } 

    bool operator()(double val) 
    { 
     std::set<double>::iterator iter = values.lower_bound(val); 
     if(iter != values.end()) 
     { 
      if(*iter - val < tolerance) 
      { 
       return false; 
      } 
     } 
     if(iter != values.begin()) 
     { 
      --iter; 
      if(val - *iter < tolerance) 
      { 
       return false; 
      } 
     } 
     values.insert(val); 
     return true; 
    } 
}; 

이 :: 당신이 좋아하는 것보다 더 많은 시간을 설정 그것에 그래서 당신이 필요하다고 생각하면 그것을 "최적화"하려고 할 수 있습니다.(다소 방해가 되기는하지만 세트로 생성하십시오. 공제에 의존하지 않고 참조를 나타 내기 위해 remove_if의 세 번째 템플릿 매개 변수를 지정할 수도 있습니다). 술어 연산자()는 비 const입니다.

관련 문제