假设我有一个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这样的算法看起来非常接近我正在寻找的东西,但只是不是正确的事情,而且从头开始自己实现它可能没有任何好处。
答案 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;
}
}
答案 1 :(得分:2)
Eric Niebler's range
library,AFAIU is in the process of becoming part of the standard library,group_by
与Python'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;
}
或
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;
}