C ++:生成未知深度的多维向量

时间:2018-01-26 06:08:15

标签: c++ multidimensional-array vector

我在C ++中有一个函数(调用它 " weightmatrix")以大小为 n 的向量作为输入,其中包含一系列数字 a b c ...,并返回 n 维度向量,该向量由大小为 c,b,a ...

听起来很复杂。基本上,在实践中它应该是这样的:

vector<int> vector_sizes = {2, 3, 1}; 
cout << "Resulting matrix: " << weightmatrix(vector_sizes); // Function takes vector of size 3
/* Returns the following 3 dimensional matrix:
   { { {0, 0}, 
       {0, 0}, 
       {0, 0} }, 
    {0, 0, 0} }
*/

我知道这是一个奇怪的事。我只需要在不事先知道的情况下生成矢量 它将具有多少维度。你可以提出的任何帮助或建议都会很棒。

2 个答案:

答案 0 :(得分:2)

我采用了Galik的提示来制作一个小样本:

#include <cassert>
#include <iostream>
#include <vector>

template <typename ELEM>
class NDArrayT {
  private:
    // dimensions
    std::vector<size_t> _dims;
    // data
    std::vector<ELEM> _data;

  public:
    NDArrayT(const std::vector<size_t> &dims):
      _dims(dims)
    {
      size_t size = _dims.empty() ? 0 : 1;
      for (size_t dim : _dims) size *= dim;
      _data.resize(size);
    }
    NDArrayT(
      const std::vector<size_t> &dims,
      const std::vector<ELEM> &data):
      NDArrayT<ELEM>(dims)
    {
      assert(_data.size() == data.size());
      std::copy(data.begin(), data.end(), _data.begin());
    }

    ELEM& operator[](const std::vector<size_t> &indices)
    {
      size_t i = 0, j = 0;
      for (size_t n = _dims.size(); j < n; ++j) {
        i *= _dims[j]; i += indices[j];
      }
      return _data[i];
    }

    const ELEM& operator[](const std::vector<size_t> &indices) const
    {
      size_t i = 0, j = 0;
      for (size_t n = _dims.size(); j < n; ++j) {
        i *= _dims[j]; i += indices[j];
      }
      return _data[i];
    }
};

using namespace std;

ostream& operator<<(ostream &out, const vector<size_t> &values)
{
  const char *sep = "";
  for (size_t value : values) {
    out << sep << value; sep = ", ";
  }
  return out;
}

bool inc(vector<size_t> &indices, const vector<size_t> &dims)
{
  for (size_t i = indices.size(); i--;) {
    if (++indices[i] < dims[i]) return false;
    indices[i] = 0;
  }
  return true; // overflow
}

int main()
{
  // build sample data
  vector<double> data(2 * 3 * 4);
  for (size_t i = data.size(); i--;) data[i] = (double)i;
  // build sample array
  typedef NDArrayT<double> NDArrayDouble;
  const vector<size_t> dims = { 2, 3, 4 };
  NDArrayDouble a(dims, data);
  // print sample array (check subscript)
  vector<size_t> indices(dims.size(), 0);
  do {
    cout << "a[" << indices << "]: " << a[indices] << endl;
  } while (!inc(indices, dims));
  // done
  return 0;
}

ideone上进行编译和测试。 输出是:

a[0, 0, 0]: 0
a[0, 0, 1]: 1
a[0, 0, 2]: 2
a[0, 0, 3]: 3
a[0, 1, 0]: 4
a[0, 1, 1]: 5
a[0, 1, 2]: 6
a[0, 1, 3]: 7
a[0, 2, 0]: 8
a[0, 2, 1]: 9
a[0, 2, 2]: 10
a[0, 2, 3]: 11
a[1, 0, 0]: 12
a[1, 0, 1]: 13
a[1, 0, 2]: 14
a[1, 0, 3]: 15
a[1, 1, 0]: 16
a[1, 1, 1]: 17
a[1, 1, 2]: 18
a[1, 1, 3]: 19
a[1, 2, 0]: 20
a[1, 2, 1]: 21
a[1, 2, 2]: 22
a[1, 2, 3]: 23

管理连续内存中的多维数组的“算术”实际上非常简单。我想,这个样本最“革命性”的想法是operator[](),它使用std::vector<size_t>为每个维度提供索引。

当我写这篇文章时,我想到了许多索引编制的替代方案。 - 幻想有很多空间......

E.g。对于线性(一维)访问,也可以提供operator[]的{​​{1}}。

答案 1 :(得分:2)

以下是使用模板MultiVector类的解决方案,该类从MultiVectorView返回operator[]

基础数据存储在普通std::vector中,但可以使用vec[x][y][z]语法进行访问。

没有检查正确的用法,只实现了非常基本的功能,但它提供了如何完成它的想法。

#include <iostream>
#include <vector>

template <typename T>
class MultiVector;

template <typename T>
class MultiVectorView {
public:
    MultiVectorView(MultiVector<T>& vec_, int index_, int dimension_) : vec(vec_), index(index_), dimension(dimension_) {}

    MultiVector<T>& vec;
    int index;
    int dimension;

    MultiVectorView& operator[](std::size_t n_index) {
        int index_multiplyer = 1;
        for (int i=0; i<dimension; ++i)
            index_multiplyer *= vec.dimensions[i];
        index += n_index*index_multiplyer;
        dimension++;
        return *this;
    }

    operator T() {
        return vec.content[index];
    }

    MultiVectorView& operator=(T val) {
        vec.content[index] = val;
        return *this;
    }
};

template <typename T>
class MultiVector {
public:
    MultiVector(std::vector<int> dimensions_) : dimensions(dimensions_) {
        int size = dimensions[0];
        for (int i = 1; i<dimensions.size(); ++i)
            size *= dimensions[i];

        content.resize(size);
    }

    MultiVectorView<T> operator[](std::size_t index) {
        return MultiVectorView<T>(*this, index, 1);
    }

    std::vector<T> content;
    std::vector<int> dimensions;
};

int main() {
    std::vector<int> v = {2,3,2};
    MultiVector<int> test(v);

    int tmp = 0;
    for (int x = 0; x < v[0]; ++x)
        for (int y = 0; y < v[1]; ++y)
            for (int z = 0; z < v[2]; ++z) {
                test[x][y][z] = tmp++;
            }

    for (int i=0; i<test.content.size(); ++i)
        std::cout << std::endl << test.content[i] << " ";

    int b = test[1][2][1];

    std::cout << std::endl << "b = " << b << std::endl << "test[0][1][1] = " << test[0][1][1] << std::endl;
}