如何使用算法填充向量的向量
Posted
技术标签:
【中文标题】如何使用算法填充向量的向量【英文标题】:How to use algorithms to fill vector of vectors 【发布时间】:2015-10-22 11:44:17 【问题描述】:我有
typedef std::vector<int> IVec;
typedef std::vector<IVec> IMat;
我想知道如何使用 std 算法填充IMat
,即如何用更少的代码执行以下操作(所有IVec
s 具有相同的大小)?
void fill(IMat& mat)
for (int i=0;i<mat.size();i++)
for (int j=0;j<mat[i].size();j++)
mat[i][j] = i*j;
PS:已经有一种用常数填充矩阵的方法会对我有所帮助。最好使用 C++11 之前的算法。
【问题讨论】:
Sice 值取决于索引......只要留在循环中。 需要初始化空向量,还是填充已经不为空的向量的值?另外,你想用基于索引的值(i*j
)填充它们,还是任何值(例如0
)都可以?
@SingerOfTheFall 不确定我是否理解您的第一个问题,我的IMat
已经初始化,即不为空。是的,这些值应该取决于指数。但是,它已经可以帮助我用常量填充它。
为了好玩,我在没有显式循环或for_each
的情况下尝试了这个,并设法使用嵌套的std::transform
来做到这一点。 coliru.stacked-crooked.com/a/96f803182ad4abad 从技术上讲,您可以将所有内容放在一行中以使其“更少代码”,但是您为什么要这样做? OP 中的简单循环更加简洁。
@AndyG 我不得不承认,我问这个问题的唯一原因是为了更好地理解如何使用算法。当然,我发布的代码完全没问题,但我不确定是否有更优雅的方式来编写它。似乎没有,而且所有建议的解决方案都使用 lambda,而我必须编写 C++11 之前的代码。值得一试;)
【参考方案1】:
最好的解决方案是您已经实施的解决方案。它利用 i
/j
作为偏移量和输入来计算算法。
标准算法必须对元素使用迭代器并且维护计数器。这种数据镜像是问题的明确标志。但它可以做到,如果你想花哨的话,即使在一条线上:
for_each(mat.begin(), mat.end(), [&](auto& i) static auto row = 0; auto column = 0; generate(i.begin(), i.end(), [&]() return row * column++; ); ++row; );
但正如所说,仅仅因为可以完成并不意味着它应该完成。解决这个问题的最佳方法是for
-loop。如果这是您的事情,甚至可以在一条线上进行:
for(auto i = 0U;i < mat.size();i++) for(auto j = 0U;j < mat[i].size();j++) mat[i][j] = i*j;
顺便说一句,我的标准算法在 Clang 3.7.0、gcc 5.1 和 Visual Studio 2015 上运行良好。但是 previously I used transform
rather than generate
。似乎有一些 implementation bugs in gcc 5.1 and Visual Studio 2015 捕获了 lambda 范围 static
变量。
【讨论】:
如果合适的话,把东西放在一行是非常“我的事”,但如果我必须决定,在 for 循环体周围省略
是被禁止的;)
@tobi303 因为换行符是免费的,所以我在我的个人代码中大量使用它们。 (连同花括号。)我认为它使它更具可读性。但归根结底,我认为在这种情况下,最重要的决定不是是否在一条线上进行,而是在for
-loop 中进行。
+1 仅针对此声明:“但正如所述,只是因为可以完成并不意味着应该完成”【参考方案2】:
我不知道这是否比双 for 循环更好,但在 C++11 中使用 STL 的一种可能方法是使用两个 for_each
,如下所示:
int i(0);
std::for_each(mat.begin(), mat.end(),
[&i](IVec &ivec)int j(0); std::for_each(ivec.begin(), ivec.end(),
[&i,&j](auto &k)k = i*j++;); ++i;);
LIVE DEMO
【讨论】:
我很确定生成的顺序不能保证 => 取决于实现,你填写了错误的值。 @deviantfan 不知道,然后惊喜。 @deviantfan 你能提供任何证据来支持这一点吗? en.cppreference.com/w/cpp/algorithm/… 将其实现为:while (first != last) *first++ = g();
。我相信 所有 迭代器算法都是顺序的。如果不是这种情况,可能会有很多问题,例如 lambdas。
@JonathanMee 在标准没有指定算法排序的任何地方,您都应该假设实现可以利用该说法来实现并行性。
for_each 是有序的(从头到尾,参见 §25.2.4.2)。为什么无序的东西对 lambdas 来说是个问题?【参考方案3】:
只是想我会进一步评论乔纳森的出色回答。
暂时忽略 c++11 语法,假设我们已经编写了一些支持类(暂时不管如何)。
我们可以想出这样的代码:
auto main() -> int
// define a matrix (vector of vectors)
IMat mat;
// resize it through some previously defined function
resize(mat, 10, 10);
// get an object that is a pseudo-container representing its extent
auto extent = extent_of(mat);
// generate values in the pseudo-container which forwards to the matrix
std::generate(extent.begin(),
extent.end(),
[](auto pxy) pxy.set_value(pxy.x * pxy.y); );
// or even
for (auto pxy : extent_of(mat))
pxy.set_value(product(pxy.coordinates()));
return 0;
100 行支持代码稍后(可迭代容器及其代理并非微不足道),这将编译和工作。
虽然很聪明,但存在一些问题:
多出 100 行代码是一件小事。 在我看来,这段代码实际上不如你的代码表现力。即,您的代码在做什么是显而易见的。对于我的,您必须对额外的 100 行代码做出一些假设或推理。 我的代码比你的代码需要很多更多的维护(和文档)有时少即是多。
【讨论】:
以上是关于如何使用算法填充向量的向量的主要内容,如果未能解决你的问题,请参考以下文章