如何分解嵌套的循环?
How do I factor out nested for loops?
很多时候,我需要对一组类数据进行批量操作。请考虑以下类:
#include <vector>
class Component {
public:
bool isFixed;
int a, b, c;
Component():
isFixed(false),
a(0), b(0), c(0)
{}
};
class System {
public:
std::vector<Component> components;
System(int numComponents):
components(numComponents)
{}
};
class Universe {
public:
std::vector<System> systems;
Universe(int numSystems, int numComponents):
systems(numSystems, System(numComponents))
{}
};
现在,对Universe
中的每个Component
执行单个操作变成了循环遍历Universe
中所有System
的所有Component
的问题:嵌套for
循环。
// Fixes a Component.
//
void fixComponent(Component& c) {c.isFixed = true;}
// Adds a number to the pieces of a Component.
//
void addToComponent(Component& cmp, double k)
{
cmp.a += k;
cmp.b += k;
cmp.c += k;
}
// Fixes all components in a Universe.
//
void fixAllComponents(Universe& universe)
{
for(std::size_t i = 0; i < universe.systems.size(); ++i) {
System& thisSystem = universe.systems.at(i);
for(std::size_t j = 0; j < thisSystem.components.size(); ++j) {
fixComponent(thisSystem.components.at(j));
}
}
}
// Adds a number to all components in a Universe.
//
void addToAllComponents(Universe& universe, double k)
{
for(std::size_t i = 0; i < universe.systems.size(); ++i) {
System& thisSystem = universe.systems.at(i);
for(std::size_t j = 0; j < thisSystem.components.size(); ++j) {
addToComponent(thisSystem.components.at(j), k);
}
}
}
编写迭代for
循环两次是可以的,但我可以轻松地对这些数据执行 20 个不同的任务,每次都必须重写双for
。不用说,这可能很容易出错。如果我能以某种方式重用迭代代码并只专注于不同的单个任务,那就太好了。
问题在迭代集合时,是否有一种标准方法可以"分解"for
循环?
尝试经过一番思考,我决定编写一个接受 2 个参数的函数,一个包含要迭代的数据的对象和一个指向执行任务的函数的指针。
void forEachComponent(Universe& u, void (*task)(Component&))
{
for(std::size_t i = 0; i < u.systems.size(); ++i) {
System& thisSystem = u.systems.at(i);
for(std::size_t j = 0; j < thisSystem.components.size(); ++j) {
task(thisSystem.components.at(j));
}
}
}
现在,如果我想修复一个组件,我可以简单地调用forEachComponent()
并传入要执行的任务。
Universe theUniverse(20, 30);
forEachComponent(theUniverse, fixComponent);
这个"解决方案"的明显问题是,对于每个涉及不同参数的任务,如addToComponent()
,我必须编写另一个函数,该函数将指针指向具有这些参数的函数,这违背了分解for
循环的目的。
您可以使用函子重用循环访问组件的逻辑。
template <typename Functor >
void forEachComponent(Universe& universe, Functor functor)
{
for(std::size_t i = 0; i < universe.systems.size(); ++i) {
System& thisSystem = universe.systems.at(i);
for(std::size_t j = 0; j < thisSystem.components.size(); ++j) {
functor(thisSystem.components.at(j));
}
}
}
// Fixes all components in a Universe.
void fixAllComponents(Universe& universe)
{
forEachComponent(universe, [](Component& c) {fixComponent(c);});
}
// Adds a number to all components in a Universe.
void addToAllComponents(Universe& universe, double k)
{
forEachComponent(universe, [k](Component& c) {addToComponent(c, k);});
}
您可以使用范围for
循环来简化forEachComponent
。
template <typename Functor >
void forEachComponent(Universe& universe, Functor functor)
{
for(System& system : universe.systems) {
for(Component& c : system.components) {
functor(c);
}
}
}
OOP 的方法是定义一个抽象类:
class Task {
void execute(Component &) = 0;
}
现在,您可以将forEachComponent()
定义为
void forEachComponent(Universe& u, Task& task)
并在 for 循环中调用task.execute()
。
或者,您可以将forEachComponet()
定义为模板:
template <class Task>
void forEachComponent(Universe& u, Task& task)
现在,传入此函数的任何内容都必须覆盖operator()
。
相关文章:
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 了解嵌套循环打印星号图案
- 无法掌握嵌套循环的写作技巧
- 在 c++ 中实现嵌套循环的更短方法吗?
- 从嵌套循环中的 std::list 中删除将返回访问冲突
- 毕达哥拉斯三重嵌套循环误解
- T(n) 表示嵌套循环
- 2 个嵌套循环的时间复杂度
- 嵌套循环背后的逻辑
- 使用 %s C++嵌套循环
- 嵌套循环和重复迭代器
- 如何在 c++ 下使用嵌套循环和正则表达式降低时间复杂度?
- C++在乘法图中放置随机值(嵌套循环)
- 如何使用 OpenMP 减少嵌套循环?
- 为什么使用 2 个嵌套循环 O(n^2) 复杂度来解决二和问题,当只改变循环计数器逻辑时运行得更快?
- 学习嵌套循环C++与示例混淆
- 如何在CUDA中嵌套循环
- std::vector上的嵌套循环
- 具有动态数组分配的OpenMP嵌套循环
- 两个嵌套循环的运行时间复杂性:二次型还是线性