是否有任何优雅的方式来遍历元素位置可以更改的列表?
Is there any elegant way of iterating through a list whose elements' positions can change?
我目前遇到了一个令人作呕的问题。假设有一个对象列表(我们称之为对象类型(,我想遍历它。基本上,代码是这样的:
for(int i = 0; i < aList.Size(); ++i)
{
aList[i].DoSth();
}
这里困难的部分是,DoSth((方法可以更改调用者在列表中的位置!因此,可能会出现两种后果:首先,迭代可能永远无法结束;其次,可能会跳过某些元素(迭代不一定像上面一样,因为它可能是链表(。当然,第一个是主要问题。
必须通过以下约束来解决问题:
1(不能排除进行换仓操作的可能性;
2(换仓操作可以延迟到迭代完成,如果必要且可行;
3(由于它经常发生,因此只能对迭代进行最小的修改(因此不建议创建列表副本之类的操作(。
我使用的语言是C++,但我认为在 JAVA 和 C# 等中也有类似的问题。
以下是我尝试过的:
a( 尝试在迭代期间禁止换仓操作。但是,这涉及太多的客户端代码文件,查找和修改所有这些文件是不切实际的。
b( 修改 Object 的每个方法(例如,Method(((,这些方法可以改变自身的位置,并且将由DoSth((直接或间接调用,这样:首先我们可以知道aList正在进行迭代,我们将相应地处理Method((。如果迭代正在进行中,那么我们延迟Method((想要做的事情;否则,它现在就做它想做的事。这里的问题是:在这里延迟函数调用的最佳(易于使用,但足够高效(的方法是什么?Method((的参数可能相当复杂。此外,这种方法还将涉及相当多的功能!
c( 尝试修改迭代过程。我在这里遇到的实际情况非常复杂,因为它涉及两层迭代:第一层是普通数组迭代,而第二层是位于递归函数中的典型链表迭代。目前,对于第二层迭代,我能做的最好的事情就是限制其迭代时间并防止同一元素多次迭代。
所以我想有更好的方法来解决这个问题吗?也许一些很棒的数据结构会有所帮助?
你的问题在细节上有点轻,但从你写的内容来看,你似乎犯了混合关注的错误。
您的对象可能会执行某些操作,导致它继续存在或不存在。它不应该再存在的决定与实际将其存储在容器中的决定是分开的。
因此,让我们将这些担忧分开:
#include <vector>
enum class ActionResult {
Dies,
Lives,
};
struct Object
{
ActionResult performAction();
};
using Container = std::vector<Object>;
void actions(Container& cont)
{
for (auto first = begin(cont), last = end(cont)
; first != last
; )
{
auto result = first->performAction();
switch(result)
{
case ActionResult::Dies:
first = cont.erase(first); // object wants to die so remove it
break;
case ActionResult::Lives: // object wants to live to continue
++first;
break;
}
}
}
如果操作确实只有两个结果,生和死,那么我们可以习惯性地表达这个迭代:
#include <algorithm>
// ...
void actions(Container& cont)
{
auto actionResultsInDeath = [](Object& o)
{
auto result = o.performAction();
return result == ActionResult::Dies;
};
cont.erase(remove_if(begin(cont), end(cont),
actionResultsInDeath),
end(cont));
}
嗯,问题解决了,至少就我现在感兴趣的情况而言。在我的情况下,aList实际上是一个链表,Object元素是通过指针访问的。如果aList的大小相对较小,那么我们有一个优雅的解决方案,就像这样:
Object::DoSthBig()
{
Object* pNext = GetNext();
if(pNext)
pNext->DoSthBig();
DoSth();
}
这有一个潜在的假设,即每个pNext在此过程中保持有效。但是,如果元素删除操作已经谨慎处理,那么一切都很好。
当然,这是一个非常特殊的例子,不能应用于其他情况。
- 如何通过保持第一个插入的位置来对列表中插入的其余元素进行排序?
- C++ 从具有开始位置和结束位置的列表中删除
- 是否有任何优雅的方式来遍历元素位置可以更改的列表?
- 在 DLL 中嵌入 Python:Py_DECREF列表对象时访问冲突读取位置
- 创建一个函数以在给定位置将元素插入到列表中
- 如何在这两个分类的链接列表之间获得开关的位置
- 试图从链接列表中删除位置
- 从方法中获得链接列表中的位置
- 在链接列表前n位置中移动某个节点
- 通过指定第 n 个节点位置在单链接列表中插入数据
- 清除临时列表而不清除我将其分配到的位置
- 在GDB中查找列表术语的位置
- 在链接列表C 中的某个位置插入节点
- 如何从列表中删除奇数位置
- 从二进制文件中获取源文件(和位置)的列表
- 在代码中的同一位置最有效地填充静态标题列表和动态值列表
- 如何根据列表中的位置删除特定项目
- C/C++:函数参数列表中的"const"位置
- 动态规划:计算连续跳跃列表的所有可能的结束位置
- 从STL列表的任何位置访问头