我有一个包含一些数据的向量。我想根据一些标准将其拆分为常数的向量。例如:
using Point=std::pair<int,int>;
std::array<std::vector<Point>,4> split_to_4(const std::vector<Point>& data,std::function<size_t(Point)> criteria);
int main(){
std::vector<Point> data;
//fill data
auto results=split_to_4(data,[](const Point& p){
if(cond1) return 0;
if(cond2) return 1;
if(cond3) return 2;
return 3;
});
}
实施split_to_4
的最佳方式是什么?我目前的尝试是:
std::array<std::vector<Point>,4> split_to_4(const std::vector<Point>& data,std::function<size_t(Point)> criteria){
std::array<std::vector<Point>,4> result;
for (const auto& p : data){
areas_regions[criteria(p)].emplace_back(p);
}
return result;
}
更好..更多std
方式吗?
更好,我的意思是:更具可读性......取决于迭代器......取决于某些标准函数......
答案 0 :(得分:5)
您可以通过多次调用std::partition
来执行此操作:
which
当然,如果您愿意,也可以直接传递和使用条件,而不是通过某些splitN
函数进行编程。
如果需要,还可以通过循环将其重写为which
。 (注意,这种方法的复杂性对于具有n个元素的范围是O(N * n)。对于大N来说这可能是不合理的慢。另一方面,我们得到掉期而不是副本,这可能有帮助,如果复制很昂贵(与调用auto
相比)。如果性能至关重要,请测量。)
如果您需要保留每个组中元素的相对顺序,std::stable_partition
就是您的朋友。
注意到C ++ 11标记:上面的代码是C ++ 14。对于C ++ 11兼容性,只需将我使用的std::array<ForwardIt, 3>
更改为显式类型,即使用const std::iterator_traits<ForwardIt>::value_type&
作为返回类型,使用survey <- surveyFromCSV
survey <- subset(survey, survey$X6 != "german")
survey <- factor(survey)
作为lambdas。
为了简洁,我将其留下,最后一段完成了前C ++ 14人的答案。
答案 1 :(得分:2)
更新
可能是最像STL的方式:
特点:
基于迭代器,因此选择源和目标容器留给调用者
如果需要移动分区,源迭代器可能是移动迭代器,或者保留为正常迭代器来制作副本
线性时间复杂度
结果的稳定排序(参考std::stable_partition
)
-
#include <array>
#include <vector>
#include <utility>
#include <cassert>
using Point=std::pair<int,int>;
// example split function - could be a function object
extern std::size_t which_bucket(const Point&);
template<class Iter, class OutIter, class Which>
auto split_n(Iter first, Iter last,
OutIter outfirst, std::size_t N,
Which&& which)
{
while (first != last) {
auto index = which(*first);
assert (index < N);
std::next(outfirst, index) -> push_back(*first);
++ first;
}
}
template<class Iter, class OutIter, class Which>
auto split_to(Iter first, Iter last,
OutIter outfirst, OutIter outlast,
Which&& which)
{
return split_n(first, last, outfirst,
std::distance(outfirst, outlast),
std::forward<Which>(which));
}
int main(){
std::vector<Point> source;
std::array<std::vector<Point>, 4> dest { };
split_n(source.begin(), source.end(),
dest.begin(), dest.size(),
which_bucket);
// or
split_to(source.begin(), source.end(),
dest.begin(), dest.end(),
which_bucket);
// or with move request:
split_to(std::make_move_iterator(source.begin()),
std::make_move_iterator(source.end()),
dest.begin(), dest.end(),
which_bucket);
}
另一种方式
#include <array>
#include <vector>
#include <utility>
using Point=std::pair<int,int>;
// example split function - could be a function object
extern std::size_t which_bucket(const Point&);
template<class Iter, class Which>
auto split4(Iter first, Iter last, Which&& which)
{
std::array<std::vector<Point>, 4> result {};
while (first != last) {
result[which(*first)].push_back(*first);
++first;
}
return result;
}
int main(){
std::vector<Point> data;
auto results = split4(data.begin(), data.end(), which_bucket);
}
这是另一种尊重向量中任何自定义分配器的方法:
#include <array>
#include <vector>
#include <utility>
using Point=std::pair<int,int>;
// example split function - could be a function object
extern std::size_t which_bucket(const Point&);
template<class T, class A, class Which>
auto split4(const std::vector<T,A>& v,
Which&& which)
{
using vec_type = std::vector<T,A>;
std::array<std::vector<T,A>, 4> result {
vec_type(v.get_allocator()),
vec_type(v.get_allocator()),
vec_type(v.get_allocator()),
vec_type(v.get_allocator())
};
for (auto& p : v) {
result[which(p)].push_back(p);
}
return result;
}
int main(){
std::vector<Point> data;
auto results = split4(data, which_bucket);
}