在我的程序中,我使用boost::multi_array,有时候将容器中元素的指针转换成索引是很重要的,例如,检查元素是否在数组的任何维度上都不在数组的边界上。
boost::multi_array<int, 2> arr2d(boost::extents[10][10]);
const auto data = arr2d.data();
const auto end = data + arr2d.num_elements();
for ( auto it = data; it != end; ++it )
{
[[maybe_unused]] int v = *it;
// how to convert it into x and y indices in arr2d?
}
boost::multi_array中是否有内置的有效方法来进行指针到索引的转换?或者唯一的可能是手动划分相对于维度上数据开始的偏移量?
2条答案
按热度按时间c0vxltue1#
这个工具似乎不在库中。这有点遗憾,但从库的接口/用例来看是有意义的。
我想出了这个解决方案,它考虑了所有的存储顺序/方向,和基本索引:
因为这是太多的逻辑不测试它我想出了一个严格的测试:
这将导致按内存顺序打印每个元素的Map坐标:
并且还检查所有元素:
然后我在各种测试矩阵上运行它:
这个打印
{{1、2}、{3、4}、{5、6}}-〉{{0、0}、{0、1}、{1、0}、{1、1}、{2、0}、{2、1}}
{{1、4}、{2、5}、{3、6}}-〉{{0、0}、{1、0}、{2、0}、{0、1}、{1、1}、{2、1}}
{{{1、7、13}、{4、10、16}}、{{2、8、14}、{5、11、17}}、{{3、9、15}、{6、12、18}}-〉{{0、0、0}、{1、0、0}、{2、0、0}、{1、1、0}、{2、1、0}、{0、0、1}、{1、0、1}、{2、0、1}、{0、1、1}、{1、1、1}、{2、1、1}、{0、0、2}、{1、0、2}、{2、0、2}、{0、1、2}、{1、1、2}、{2、1、2}}
{{{1、7、13}、{4、10、16}}、{{2、8、14}、{5、11、17}}、{{3、9、15}、{6、12、18}}-〉{{50、-20、100}、{51、-20、100}、{52、-20、100}、{50、-19、100}、{51、-19,100},{52,-19,100},{50,-20,101},{51,-20,101},{52,-20,101},{50,-19,101},{51,-19,101},{52,-19,101},{50,-20,102},{51,-20,102}、{52、-20、102}、{50、-19、102}、{51、-19、102}、{52、-19、102}}
{{{9、10、11、12}、{21、22、23、24}、{{5、6、7、8}、{17、18、19、20}、{{1、2、3、4}、{13、14、15、16}}-〉{102、100、100}、{102、100、101}、{102、100、102}、{102、100、103}、{101、100、100}、{101、100、101}、{101、100、102}、{101、100、103}、{100、100、100}、{100、100、101}、{100、100、102}、{100、100、103}、{102、101、100}、{102、101、101}、{102、101、102}、{102、101、103}、{101、101、100}、{101、101、101}、{101、101、102}、{101、101、103}、{100、101、100}、{100、101、101}、{100、101、102}、{100、101、103}}共检查了72个元素,验证结果正常
完整列表
g2ieeal72#
虽然@sehe的答案是正确的,也是相当一般的,但下面是针对您的特定情况的解决方案:
这也显示了这种方法的一个缺陷,即整数除法和取模(尽管可能融合在一个运算中)通常是CPU中相当昂贵的运算(与整数加法和乘法相比)。
所以,如果循环中的主操作很便宜,那么你基本上要为这些昂贵的代数操作付出代价(Sehe的解决方案不是灵丹妙药,它也有这个缺点,看看他代码中间的除法)。
在这种情况下,您必须做的是,如果您确实需要重新构建索引,最好首先从索引开始)。
这里的双循环不是主要的,它最终可以被
std::cartesian_product
或者一个等价的自定义范围所取代,关键是从索引到内存中的位置比反向操作要便宜。