根据一些标准拆分std :: vector

时间:2016-06-17 14:25:20

标签: c++ arrays c++11 vector

我有一个包含一些数据的向量。我想根据一些标准将其拆分为常数的向量。例如:

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方式吗?

更好,我的意思是:更具可读性......取决于迭代器......取决于某些标准函数......

2 个答案:

答案 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的方式:

特点:

  1. 基于迭代器,因此选择源和目标容器留给调用者

  2. 如果需要移动分区,源迭代器可能是移动迭代器,或者保留为正常迭代器来制作副本

  3. 线性时间复杂度

  4. 结果的稳定排序(参考std::stable_partition

  5. -

    #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);
    }