std::уникальное слияние

#c #algorithm

#c #алгоритм

Вопрос:

Я использую std::unique для объединения кластеров в вектор с плавающей точкой, используя метод equals с большим эпсилоном. Проблема в том, что он выполняет запуски, подобные 1, и превращает их в 2.
Хотя я хочу, чтобы он объединял их, как при использовании среднего значения по «равным» точкам, превратите их в 3.

 (1) ...               .      ....    .....
(2) .                 .      .       .
(3)  .                .       .        .
 

Как я могу это сделать, используя стандартную библиотеку C ?

Комментарии:

1. Каков формат данных? Это не может быть просто std::vector<float> так, иначе вы потеряете позиционирование. Если я вас не неправильно понял.

2. @MooingDuck: так и есть, значение — это позиция. первый из них похож на 1,2,3,20,25,26,27,28,35,36,37,38,39.

3. Всегда ли «запуски» являются последовательными?

4. Я считаю, что было бы проще просто написать алгоритм самостоятельно, а не создавать какой-то супер предикат, который будет усреднять вещи для вас.

5. «метод equals с большим эпсилоном» не является отношением эквивалентности, поэтому его std::unique вообще нельзя использовать.

Ответ №1:

Нет, нет стандартного алгоритма, который может делать то, что вы хотите. Тем не менее, это не невероятно сложно. Я попытался сделать минимальные предположения об итераторах, поэтому это должно работать с любым итератором прямого ввода.

 #include <iostream>

template<class initer, class outiter, class predicate>
outiter average_runs(initer begin, initer end, outiter out, predicate pred) {
    //quit if no range
    if (begin == end)
        return out;
    initer endrun = begin; 
    do {
        //find end of run
        while(endrun 1 != end amp;amp; pred(*endrun,*(endrun 1)))
              endrun;
        //move "begin" to the middle
        std::advance(begin, std::distance(begin,endrun)/2);
        //output the result
        *out   = *begin;
        //start next run
        begin =   endrun;
    } while(endrun != end);
    return out;
}

bool intclose(int l, int r) 
{ return r-l <= 1;}
int main() {
    int array[13] = {1,2,3,20,25,26,27,28,35,36,37,38,39};
    int output[13] = {};
    int* end = average_runs((int*)array, array 13, (int*)output, amp;intclose);
    for(int* c = output; c<end;   c)
        std::cout << *c << ' ';
    return 0;
}
//displays: 2 20 26 37
 

Комментарии:

1. Выражение (endrun-begin) не гарантируется для прямого итератора.

2. Также я не могу найти гарантии, что если fwditer a=b; b ; a ; это a и b «указать» на одно и то же «местоположение». Это означает, что итераторы istream, вероятно, с треском провалятся в этом и подобных алгоритмах.

3. Было бы поистине чудесно, если бы вы могли найти середину ряда, даже не зная, каким будет следующее число, не так ли? 😉

4. Если бы желания были лошадьми, у меня были бы крылья! (или что-то в этом роде)