假设
b = ["good ", "bad "]
a = ["apple","mango"]
then output = ["good apple","good mango","bad apple","bad mango"]
我知道可以使用嵌套的for循环来完成这个任务,但是否有一行优雅的代码使用C++ STL来完成呢?
给定vector<string> a
和vector<string> b
,您可以使用for_each
:
vector<string> output(size(a) * size(b));
for_each(begin(output), end(output), [&, it = 0U](auto& i) mutable {
i = a[it / size(b)] + ' ' + b[it % size(b)];
++it;
});
编辑:
我们已经初始化了 output
,使其能够容纳每个 a
和 b
的组合。然后我们将遍历每个 output
元素并进行赋值。
我们将想要使用 a
的第一个元素来填充 output
的前 size(b)
个元素,并使用 a
的第二个元素来填充接下来的 size(b)
个元素,以此类推。因此,我们将使用 it / size(b)
进行索引。我们还需要通过迭代 b
的元素来完成这一操作。
it
将在每个 output
元素上移动到下一个索引,但索引需要进行循环,否则当 it == size(b)
时,它将越界,为了解决这个问题,我们使用 it % size(b)
。
编辑2:
在这个问题中,通过基准测试我发现取模和除法是迭代的昂贵操作。我在这里进行了相同的测试。为了隔离算法,我只在一个 vector<int>
上执行笛卡尔求和,而不是 vector<string>
。
首先我们可以看到两个算法的汇编结果不同。我上面写的算法需要 585 行代码。我对MSalter 的代码的解释需要 588 行。
vector<string> output(size(testValues1) * size(testValues2));
auto i = begin(output);
std::for_each(cbegin(a), cend(a), [&](const auto& A) { std::for_each(cbegin(b), cend(b), [&](const auto& B) { *i++ = A + ' ' + B; }); });
a
的cend(a)-cbegin(a)
个元素写入output
。 - MSaltersfor_each(begin(output), end(output), [&, it = 0U](auto& i) mutable { i = a[it / size(b)] + ' ' + b[it % size(b)]; ++it; });
- Jonathan Mee这是一行代码(从Jonathan Mee的答案复制而来):
for(size_t i = 0, s = a.size(); i < output.size(); ++i) output[i] = b[i/s] + ' ' + a[i%s];
Full example here.
std::string
比循环中发生的其他任何事情都要昂贵得多,所以这种修改实际上只是噪音”。就像把一盒饼干放在你车子的后备箱里一样——它实际上并不会影响你的里程数 =)。 - Matteo Italia目前没有直接的解决方案;我检查了整个<algorithm>
,没有任何函数可以产生长度为M*N的输出。
您可以在第一个范围上调用std::for_each
,使用一个lambda函数,在其中调用第二个范围上的std::for_each
!
std::vector<std::string> a, b;
std::for_each(a.begin(), a.end(),
[&](std::string A) { std::for_each(b.begin(), b.end(),
[A](std::string B) { std::cout << A << '/' << B << '\n'; }
);});
但那只是STL中的嵌套循环。
push_back
以外的方式迭代地分配给vector
,因为这种方式已知速度较慢。我已经修改了您的算法,用于基准测试。欢迎任何评论。 - Jonathan Mee.reserve()
并不会太糟糕。 - MSalters.reserve
方法。 - MSalters
for (auto i : a) for (auto j : b) output.push_back(i + ' ' + j);
真的吗? - Nim