问题描述
我正在尝试运行以下 foreach 循环,以便删除特定条目。
textMap.results.forEach((element) {
textMap.results.removeAt(**element.KEY**);
print(element.KEY)
}
是否可以引用 foreach 循环的索引/键?? 我已经使用基本迭代器对此进行了测试,但是如果列表包含多个需要删除的条目,那么一旦删除了初始项目,索引就会变得不同步。这就是为什么我要寻找索引/键
解决方法
首先,avoid using Iterable.forEach
except for trivial cases。如果您需要元素索引,只需使用普通的循环结构(例如 for
、while
)。另见https://stackoverflow.com/a/65420010/。
在您的示例代码中,您无条件地删除了每个项目,因此您可以在最后调用 List.clear()
,这样会更简单、更高效。那应该是 O(1)。
如果您不想删除所有项目,而是需要有条件删除多个项目,您可以通过几种方法来实现。
-
如果可能,请使用
List.removeWhere
。我希望这对于列表的长度是 O(n)。 -
从最后到第一项处理项目,以便从列表中删除元素不会影响迭代:
for (var i = textMap.results.length - 1; i >= 0; i -= 1) { print(textMap.results[i]); // Do something with the element. if (shouldRemove(textMap.results[i])) { textMap.results.removeAt(i); } }
-
如果一定要按顺序处理元素,可以先收集一个要删除的索引列表,然后再分别删除:
var indicesToRemove = <int>[]; for (var i = 0; i < textMap.results.length; i += 1) { print(textMap.results[i]); // Do something with the element. if (shouldRemove(textMap.results[i])) { indicesToRemove.add(i); } } // Remove in reverse order so that removing items does not affect // unprocessed indices. for (var index in indicesToRemove.reversed) { textMap.results.removeAt(index); }
-
或者使用
while
循环有条件地增加列表索引:var i = 0; while (i < textMap.results.length) { print(textMap.results[i]); // Do something with the element. if (shouldRemove(textMap.results[i])) { textMap.results.removeAt(i); // Iterate again at the same index. continue; } i += 1; }
最后三种方法是 O(m*n),其中 n 是列表的长度,m 是要删除的项目数。