如何计算向量中相等,相邻的元素?

时间:2016-09-20 14:06:47

标签: c++ algorithm vector stl

假设我有一个vector<int> { 1, 1, 2, 3, 3, 3, 1, 1 },我想将其转换为vector<std::pair<int, int>> { {1, 2}, {2, 1}, {3, 3}, {1, 2} }相邻的元素数量&#39;:

我可能会在向量上迭代,并带有一个标志,指示新邻接集的开始&#39;以及计算连续元素数量的计数器。我只是想知道在STL中是否已经没有更抽象和更优雅的解决方案,因为这似乎是一个非常常见的用例。像unique,adjacent_find或equal_range这样的算法看起来非常接近我正在寻找的东西,但只是不是正确的事情,而且从头开始自己实现它可能没有任何好处。

4 个答案:

答案 0 :(得分:4)

从算法的角度来看,最接近的是run-length encoding我会说。我不认为有一个现成的算法可以做到这一点,但代码应该是微不足道的:

std::vector<std::pair<int, int>> out; 
for (int i: in)
{
     if (out.empty() || out.back().first != i)
     {
         out.emplace_back(i, 1);
     }
     else
     {
         ++out.back().second;
     }
}

Live-example.

答案 1 :(得分:2)

Eric Niebler's range libraryAFAIU is in the process of becoming part of the standard librarygroup_byPython's itertools.groupby非常相似,并根据需要对连续的等效元素进行分组。

要对矢量进行分组,请先从

开始
const vector<int> l{ 1, 1, 2, 3, 3, 3, 1, 1 };
auto x = l | view::group_by(std::equal_to<int>());

这意味着x是一个视图,其中相邻的整数属于一个组,如果整数相等。

现在要迭代,然后说,打印每个连续的组及其大小,你可以执行以下操作(我确信你可以做得比以下更好,但这是我使用这个库的限制):

for (auto i = x.begin();i != x.end(); ++i) 
    cout <<  *((*i).begin()) << " " << to_vector(*i).size() << endl;

示例

#include <vector>
#include <iostream>
#include <range/v3/all.hpp>

int main(int argc, char **argv) { 
    const std::vector<int> l{ 1, 1, 2, 3, 3, 3, 1, 1 };
    auto x = l | ranges::view::group_by(std::equal_to<int>());

    for (auto i = x.begin();i != x.end(); ++i) 
        std::cout <<  *((*i).begin()) << " " << ranges::to_vector(*i).size() << std::endl;
}

打印出来

$ ./a.out 
1 2
2 1
3 3
1 2

答案 2 :(得分:0)

据我所知,没有这样的C ++库可以自动完成您的要求 无论如何,实现这一点非常简单。这是一种方式:

#include <iostream>
#include <vector>

using namespace std;

void count_equal_elements(vector<int>& vec, vector<pair<int,int> >& result){
    if (vec.empty())
        return;
    int curr = vec[0];
    int count = 1;
    for (vector<int>::iterator it = vec.begin()+1; it != vec.end(); ++it){
        if (curr == *it){
            count++;
        }
        else{
            result.push_back(make_pair(curr,count));
            curr = *it;
            count = 1;
        }
    }
    result.push_back(make_pair(curr,count));
}

ideone中查看。

答案 3 :(得分:0)

使用std,您可以执行以下操作:

template <typename T>
std::vector<std::pair<T, std::size_t>>
adjacent_count(const std::vector<T>& v)
{
    std::vector<std::pair<T, std::size_t>> res;

    for (auto it = v.begin(), e = v.end(); it != e; /*Empty*/) {
        auto it2 = std::adjacent_find(it, e, std::not_equal_to<>{});
        if (it2 != e) {
            ++it2;
        }
        res.emplace_back(*it, std::distance(it, it2));
        it = it2;
    }
    return res;
}

Demo

template <typename T>
std::vector<std::pair<T, std::size_t>>
adjacent_count(const std::vector<T>& v)
{
    std::vector<std::pair<T, std::size_t>> res;

    for (auto it = v.begin(), e = v.end(); it != e; /*Empty*/) {
        const auto it2 = std::find_if(it, e, [&](const auto&x) { return x != *it; });
        res.emplace_back(*it, std::distance(it, it2));
        it = it2;
    }
    return res;
}

Demo