我遇到了一些简单的C#代码问题,我很容易在C / C ++中修复它。 我想我错过了一些东西。
我想执行以下操作(修改列表中的项目):
//pseudocode
void modify<T>(List<T> a) {
foreach(var item in a) {
if(condition(item)) {
item = somethingElse;
}
}
}
我理解foreach循环集合被视为不可变,因此上面的代码无法工作。
因此,我尝试了以下内容:
void modify<T>(List<T> a) {
using (var sequenceEnum = a.GetEnumerator())
{
while (sequenceEnum.MoveNext())
{
var m = sequenceEnum.Current;
if(condition(m)) {
sequenceEnum.Current = somethingElse;
}
}
}
}
天真地认为Enumerator是我的Element的某种指针。显然,调查员也是不可改变的。
在C ++中我会写这样的东西:
template<typename T>
struct Node {
T* value;
Node* next;
}
然后能够修改*value
而不触及Node
中的任何内容,因此在父集合中:
Node<T>* current = a->head;
while(current != nullptr) {
if(condition(current->value))
current->value = ...
}
current = current->next;
}
我真的不得不使用不安全的代码吗?
或者我是否在循环中调用下标的可怕性?
答案 0 :(得分:4)
您还可以使用简单的for
循环。
void modify<T>(List<T> a)
{
for (int i = 0; i < a.Count; i++)
{
if (condition(a[i]))
{
a[i] = default(T);
}
}
}
答案 1 :(得分:2)
简而言之 - 不要修改列表。你可以用
达到预期的效果a = a.Select(x => <some logic> ? x : default(T)).ToList()
一般来说,C#中的列表在迭代期间是不可变的。你可以继续使用。删除所有或类似的方法。
答案 2 :(得分:1)
使用类似的东西:
List<T> GetModified<T>(List<T> list, Func<T, bool> condition, Func<T> replacement)
{
return list.Select(m => if (condition(m))
{ return m; }
else
{ return replacement(); }).ToList();
}
用法:
originalList = GetModified(originalList, i => i.IsAwesome(), null);
但这也会让您在跨线程操作中遇到麻烦。尝试尽可能使用不可变实例,尤其是使用IEnumerable。
如果你真的想修改list的实例:
//if you ever want to also remove items, this is magic (why I iterate backwards)
for (int i = list.Count - 1; i >= 0; i--)
{
if (condition)
{
list[i] = whateverYouWant;
}
}
答案 3 :(得分:1)
如文档here中所述,System.Collections.Generic.List<T>
是System.Collections.ArrayList
的通用实现,在索引访问器中具有O(1)复杂性。非常像C ++ std::vector<>
,插入/添加元素的复杂性是不可预测的,但访问是时间常数(复杂性方面,关于缓存等)。
您的C ++代码段的等效内容为LinkedList
至于您的集合在迭代过程中的不变性,GetEnumerator
方法here的文档中明确说明了这一点。实际上,在枚举期间(foreach
内,或直接使用IEnumerator.MoveNext
):
枚举器可用于读取集合中的数据,但它们 不能用于修改底层集合。
此外,修改列表将使枚举器无效并且通常会抛出异常:
只要收集仍然存在,枚举器仍然有效 不变。如果对集合进行了更改,例如添加, 修改或删除元素,枚举器是不可恢复的 无效,其行为未定义。
我相信各种类型的集合之间的接口契约一致性会导致您的误解:它可能实现一个可变列表,但接口契约不需要它。
想象一下,您希望实现一个在枚举期间可变的列表。枚举器是否会引用(或检索)条目或条目本身?条目本身将使其不可变,例如,在链接列表中插入元素时,引用将无效。
如果你想使用标准的Collections库,@ Igor提出的简单的for循环似乎是最好的方法。否则,您可能需要自己重新实现它。