协议缓冲区 - 存储双精度数组,包括1D、2D和3D

26
如何使用协议缓冲区存储双精度数组(1D)?多维稠密数组(2D或3D)呢?

b1nary.atr0phy,这个问题有关于一维数组的解决方案;这个问题也与C/C++有关,而不是.NET。如果我们将我的问题注册为重复,答案会被合并吗? - osgx
3个回答

33

可以简单地模仿C/C++的内存布局:

message DoubleMatrix {
  required uint32 rows = 1;
  required uint32 cols = 2;
  repeated double data = 3 [packed=true];
}

要访问数据,请使用data [i * cols + j](行主要)或data [i + rows * j](列主要)。对于方阵,只需存储rows/cols之一。即使在矩形情况下,protobuf也将知道数据的长度,并且可以推导出另一个值。
为了方便使用,人们可能会用C ++中的适配器类包装矩阵,以允许通过double MatrixAdapter :: get(int row,int col)进行访问;它还可以验证data_size()== rows()* cols()

31

一个双精度数组最好通过以下方式存储:

repeated double foo = 5 [packed=true];

repeated使其作为列表,允许多个项目; packed避免每个项目的标题。

protobuf中没有直接支持矩形(或更高维度)数组。最接近的方法是存储类似于:

repeated innerType foo = 5; // note, can't be "packed"

message innerType {
    repeated double foo = 1 [packed=true];
}

这与嵌套数组类似,但每层之间都有一个元素。


4
请将 "broadly akin to a jagged array" 翻译成更符合编程术语的英语。 - osgx
6
相较于“一个数组中包含多个数组”,更应该说是“一个对象数组,每个对象具有一个数组”- 这样表述更好吗? - Marc Gravell
1
@osgx 不,那将是重复的;protobuf 将负责长度。 - Marc Gravell
1
虽然这是一个正确的解决方案,但它使用的存储空间比将矩阵存储为@smilingthax在另一个答案中建议的一维数组更多。 - mimarcel

1
如果你的主要目标是更密集的JSON表示,你可以在第二维中使用“已知类型”[google.protobuf.ListValue][1]。
import "google/protobuf/struct.proto";
message DoubleMatrix {
  uint32 cols = 1;
  uint32 rows = 2;
  repeated google.protobuf.ListValue values = 3;
}

这将在将数据编组为JSON时生成一个数组的数组。
{
  "cols": 2,
  "rows": 2,
  "values": [[1, 2], [3, 4]]
}

缺点是ListValue类型在内部使用了一个使用one-of模式的内部类型来表示值。这可能比使用自己的内部类型更加繁琐,而不需要所有的魔法。[1] https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.ListValue

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接