在模板中调整递归嵌套向量的大小

Posted

技术标签:

【中文标题】在模板中调整递归嵌套向量的大小【英文标题】:Resize recursive nested vector in template 【发布时间】:2016-09-26 10:18:23 【问题描述】:

我正在尝试制作一个模板函数来调整嵌套向量的所有维度。

很像这样:resizing multidimensional vector,但对于任意 nr。暗淡。

(我想)该函数将(至少)接受对向量(或vector<vector<T>>v<v<v<T>>> 等)的引用和具有所需大小的向量。我现在在尺寸向量中也有 in 索引,但可能不需要它。

到目前为止,这是我最终的结果(可能完全错误):

template<typename V> void resize(vector<V> & V1, vector<int32_t> t, int32_t index) 
    int32_t current_size=t.at(index); 
    cout << "resize dim [" << index << "] to size " << current_size <<endl ;
    ++index;
    if (index < t.size()) 
        // for each element ??
        // for( int i = 0 ; i < V1.size(); i++ )  resize (V1.at(i), t, index);  // doesn't work
        // for( auto const& e : V1 )  resize (e, t, index);  // doesn't work
         // resize( V1, t, index); // recursive call, works, but doesn't do anything
    

我想避免复制 V1 或其任何内容。我不确定是否有一种方法可以使用迭代器或 for 循环来传递引用。如果没有,可能需要第四个输入来保持 V1 的索引?

顺便说一句,我故意跳过第一个暗淡,它已经是正确的大小。

任何帮助表示赞赏。

【问题讨论】:

什么是向量中的“所有维度”? Hayt:每个嵌套向量的一维。所以vector,一个dim,vector>两个dim,等等。 @Wiebe 您可以发布您的代码作为替代答案(我认为在 SO 的问题中发布答案不是一种好方法) @W.F.好的,会的。 【参考方案1】:

您可能正在寻找类似的东西(这是符合 c++14 的解决方案,类似的解决方案对于 c++11 会有点棘手,但仍然可能):

#include <vector>
#include <tuple>
#include <utility>

template <class NestedVectorElement, class Tuple>
void nested_resize(std::vector<std::vector<NestedVectorElement>> &v, Tuple &&t);

template <class VectorElement, class Tuple>
void nested_resize(std::vector<VectorElement> &v, Tuple &&t);

template <class Vector, class Tuple, size_t... Is>
void nested_resize_impl(Vector &v, Tuple &&t, std::index_sequence<Is...>) 
   v.resize(std::get<0>(t));
   for(auto &nv: v) 
      nested_resize(nv, std::forward_as_tuple(std::get<Is + 1>(t)...));
   


template <class NestedVectorElement, class Tuple>
void nested_resize(std::vector<std::vector<NestedVectorElement>> &v, Tuple &&t) 
   nested_resize_impl(v, t, std::make_index_sequence<std::tuple_size<Tuple>::value - 1>);


template <class VectorElement, class Tuple>
void nested_resize(std::vector<VectorElement> &v, Tuple &&t) 
   v.resize(std::get<0>(t));


int main() 
   std::vector<std::vector<std::vector<int>>> matrix;
   nested_resize(matrix, std::make_tuple(3, 2, 3));
   matrix.at(2).at(1).at(2) = 0; // at gives you an access only if element exists else throws an exception

【讨论】:

谢谢。它确实帮助修复了我的代码中的一些细节,并且我得到了它的工作。 您建议的代码是否比我发布的工作解决方案更有效(或更好)? @Wiebe 很高兴听到它:) @Wiebe 除了恕我直言,调用方式有点繁琐,我实际上认为您的解决方案可以在相同的时间复杂度下工作【参考方案2】:

这里真正的问题是模板的每个实例都需要为两种可能性生成代码:多维向量的最后一个维度,以及向量的所有其他维度。而在后者的情况下,需要对向量的以下维度进行递归,这在前者的情况下会导致明显的编译错误。

这需要专业化:

#include <vector>
#include <iostream>

template<typename V, typename iter_type>
class resize_dim 

public:
    static void resize(V & V1,
               iter_type b, iter_type e)
    
        if (b == e)
            return;

        V1.resize(*b);
    
;

template<typename V, typename iter_type>
class resize_dim<std::vector<std::vector<V>>, iter_type> 

 public:

    static void resize(std::vector<std::vector<V>> & V1,
               iter_type b, iter_type e)
    
        if (b == e)
            return;

        V1.resize(*b);

        ++b;

        for (typename std::vector<std::vector<V>>::iterator
                 vb=V1.begin(),
                 ve=V1.end(); vb != ve; ++vb)
            resize_dim<std::vector<V>, iter_type>::resize(*vb, b, e);
    
;

template<typename V>
void resize(V &v, const std::vector<size_t> &dimensions)


    resize_dim<V, std::vector<size_t>::const_iterator>
        ::resize(v, dimensions.begin(), dimensions.end());


int main()

    std::vector<std::vector<std::vector<int>>> v;

    std::vector<size_t> d;

    d.push_back(3);
    d.push_back(3);
    d.push_back(3);

    resize(v, d);

    std::cout << "Ok" << std::endl;
    return 0;

大小向量,给出每个维度的大小应该与向量中的维度数相匹配。多余的尺寸会被忽略。较小的尺寸只会导致前导尺寸被调整大小。

【讨论】:

谢谢。我必须弄清楚现在要使用哪种解决方案,或者每种解决方案的过去。你是对的,这里有错误的空间,所以在某些时候最好创建一个嵌入 nr 的类。暗淡、暗淡大小和嵌套向量,在...【参考方案3】:

这行得通:

    template<typename V> void resizer(V & V1, vector<int32_t> const & t, int32_t index) 

    template<typename V> void resizer(vector<V> & V1, vector<int32_t> const & t, int32_t index) 
        int32_t current_size=t.at(index); 
        V1.resize(t.at(index) );
        ++index;
        if (index < t.size() ) 
            for( auto & e : V1 )  
                resizer (e , t, index);
            
        
    

但这实际上要好一些,因为我们没有不必要地迭代最后一个维度的元素:

    template<typename V> void resizer(vector<V> & V1, vector<int32_t> const & t, int32_t index) 
        int32_t current_size=t.at(index); 
        V1.resize(t.at(index) );
    

    template<typename V> void resizer(vector<std::vector<V>> & V1, vector<int32_t> const & t, int32_t index) 
        int32_t current_size=t.at(index); 
        V1.resize(t.at(index) );
        ++index;
        if (index < t.size() ) 
            for( auto & e : V1 )  
                resizer (e , t, index);
            
        
    

【讨论】:

以上是关于在模板中调整递归嵌套向量的大小的主要内容,如果未能解决你的问题,请参考以下文章

如何在 vue.js 模板中编写递归嵌套循环?

自调整大小的集合视图在 iOS 15 中进入递归循环

展平 n 维向量

不使用向量、大小或其他参数的递归回文检查

是否有支持递归之类的javascript模板引擎?

递归调整jpg大小