【问题标题】:How to count non-empty vector in a vector recursive type如何计算向量递归类型中的非空向量
【发布时间】:2023-03-05 23:31:02
【问题描述】:

我有一种类型,可以定义为向量的向量 ... 整数类型的向量。示例:

std::vector<std::vector<std::vector<std::vector< std::vector<signed char> > > > > _data;

我正在寻找一种优雅的方法来确定更深层次的非空向量的数量。对于该示例,我可以使用 4 封装循环来做到这一点,例如

for (it0 = data.cbegin() ; it0 != _data.cend() ; ++it0)
 for (it1 = *it0.cbegin() ; it1 != *it0.cend() ; ++it1)
   for (it2 = *it1.cbegin() ; it2 != *it1.cend() ; ++it2)
      for (it3 = *it2.cbegin() ; it3 != *it2.cend() ; ++it3)
          nonEmpty += (unsigned int) (*it3.empty());

但是我怎样才能创建一个模板(以支持向量、列表或任何类型的容器共享相同的 API)函数来为任何深度(超过 4 级)做到这一点?我认为递归是正确的方法,但不知道如何使用 Template ...

欢迎所有帮助和建议,因为我很确定有不止一种解决方案。

【问题讨论】:

  • 解决方案是否允许使用 C++11?
  • 不是问题的一部分,仅限 C++98 !

标签: c++ stl c++98


【解决方案1】:

这是一个 C++98 解决方案,仅使用基本模板特化:

template<typename T> struct VectorCounter {
    /* no count method: this is an error */
};

template<typename U> struct VectorCounter<vector<U> > {
    static int count(const vector<U> &v) {
        return (int)v.empty();
    }
};

template<typename V> struct VectorCounter<vector<vector<V> > > {
    static int count(const vector<vector<V> > &v) {
        int ret = 0;
        for(typename vector<vector<V> >::const_iterator it=v.cbegin(); it!=v.cend(); ++it) {
            ret += VectorCounter<vector<V> >::count(*it);
        }
        return ret;
    }
};

template<typename T> int count_nonempty_vectors(const T &v) {
    return VectorCounter<T>::count(v);
}

经过以下测试(此测试代码使用auto作为扩展,因为我很懒):

#include <iostream>
#include <vector>
using std::vector;

typedef vector<vector<vector<vector<vector<signed char> > > > > data_t;

int count_fixed(const data_t &data) {
    int nonEmpty = 0;
    for (auto it0 = data.cbegin() ; it0 != data.cend() ; ++it0)
        for (auto it1 = it0->cbegin() ; it1 != it0->cend() ; ++it1)
            for (auto it2 = it1->cbegin() ; it2 != it1->cend() ; ++it2)
                for (auto it3 = it2->cbegin() ; it3 != it2->cend() ; ++it3)
                    nonEmpty += (unsigned int)(it3->empty());
    return nonEmpty;
}

data_t build_data() {
    data_t data(5);
    int sz = 0;
    for (auto it0 = data.begin() ; it0 != data.end() ; ++it0) {
        it0->resize(4);
        for (auto it1 = it0->begin() ; it1 != it0->end() ; ++it1) {
            it1->resize(3);
            for (auto it2 = it1->begin() ; it2 != it1->end() ; ++it2) {
                it2->resize(2);
                it2->at(0).resize(1);
                it2->at(1).resize(0);
            }
        }
    }
    return data;
};

int main() {
    std::cout << count_fixed(build_data()) << std::endl;
    std::cout << count_nonempty_vectors(build_data()) << std::endl;
    return 0;
}

两者都打印出“60”。

【讨论】:

  • 我使用了那个解决方案,主要是因为它适用于 C++98,即使我必须将 'empty()' 切换为 '!empty()' :)
【解决方案2】:

也许是这样的? (它使用std::enable_if,所以它是 C++11 的答案,但也许你可以使用 boost 代替)。

template <typename T, typename U>
typename std::enable_if<std::is_same<typename U::value_type,T>::value,std::size_t>::type
non_empties(const U& r)
{
    return !r.empty();
}

template <typename T, typename U>
typename std::enable_if<!std::is_same<typename U::value_type,T>::value,std::size_t>::type
non_empties(const U& r)
{
    std::size_t res = 0;
    for(auto& it : r)
    {
        res += non_empties<T>(it);
    }
    return res;
}

用法:

auto non_empty_terminal = non_empties<signed char>(_data);

你必须把'stop'类型作为模板参数,所以可能不太理想。

现场样例here

【讨论】:

  • 感谢它是一个非常好的代码,我想我需要阅读它很多次才能完全理解它是如何工作的,但据我所知,它应该适用于任何存在空 api 的容器,所以 deque list etc cplusplus.com/reference/stl 那你为什么说它只适用于矢量?
  • 好吧,它应该适用于每个带有 value_type 字段的 continer,但例如 std::map 的 value_type 是一对,所以你必须把 T = std::pair,这并不简单。
  • @alexbuisson 是的,适用于其他 STL 容器类型,例如 std::setstd::deque,在 Live Example 链接中添加了测试。
  • 嗨,不要检查你的答案,即使它是一个完全有效的方法,一开始我虽然使用 boost/utilities 我可以将 C++11 代码移植回旧的使用 C++98 编译器的年龄,但我失败了……但这个好工作非常好,它展示了 C++11 的强大功能!
【解决方案3】:

你可以做模式匹配来计算深度

template <typename Base>
struct NestedVectors //non vector match
{
   static const size_t depth=0;
   static size_t count_empty(const Base& b)
   {
      throw std::string("cant be here");
    }

};

template <class Rv>
struct NestedVectors<std::vector<Rv> >
{
   static const size_t depth=1 + NestedVectors<Rv>::depth ;
   static size_t count_empty(const std::vector<Rv>& vec)
   {
       size_t r=0;
       if(NestedVectors<Rv>::depth == 0)
       {
            if(vec.empty())
                return 1;
       }
       else
       {
           for(size_t i =0; i < vec.size() ; ++i)
           {
               r+=NestedVectors<Rv>::count_empty(vec[i]);
           }
       }
       return r;
   }
};
int main()
{
    typedef std::vector<
       std::vector<
         std::vector<
           std::vector<
             std::vector<
               signed char
        > > > > > data_t;
   data_t t;
   std::cout << NestedVectors<data_t>::depth << " " << NestedVectors<data_t>::count_empty(t);
}

【讨论】:

  • 即使代码真的很好,问题是在最深层次计算非空容器的数量。不过谢谢
  • @alexbuisson 这应该可以,我没有测试太多,只是编译
猜你喜欢
  • 2018-12-30
  • 2019-05-04
  • 1970-01-01
  • 2014-09-02
  • 2014-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-13
相关资源
最近更新 更多