在迭代过程中修改字典(不,不是同一个问题) [英] Modifying Dictionary while Iterating through it (no, not the same question)

查看:48
本文介绍了在迭代过程中修改字典(不,不是同一个问题)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上下文:我正在使用Unity3D的OnGUI {}(每帧更新几次,非常频繁)。


通过myDic迭代:


 foreach(KeyValuePair< string,float []> this.myDic中的keyValuePair)
{
//伟大的东西
}




现在,我知道我无法修改字典在迭代时......但是对于所有情况都是如此吗?例如,  this:

 if(!this.myDicBusy)
{
foreach(KeyValuePair< string,float []> key.alDic中的keyValuePair)
{
if(event1)
{
this.myDicBusy = true;
this.myDic.Remove(keyValuePair.Key);
this.myDicBusy = false;
}
}
}


将产生 同步 即可。现在,我想我明白为什么故障保护bool var在这里不起作用(尽管如果有人愿意总结,更深入的解释会很好),但是,
添加:

 if(!this.myDicBusy)
{
foreach(KeyValuePair< string,float []> keyValuePair in this.myDic)
{
if(event2)
{
this.myDicBusy = true;
this.myDic.Add(newstuff);
this.myDicBusy = false;
}
}
}

永远不会导致不同步 。为什么会这样?



P.S 。是的,我知道,如果我想在"迭代"时修改那种类型的字典。通过它,我可以创建一个新的
myDic.Keys 列表并进行迭代,但这是正是我要避免的事情
- 创建每个新的列表<> 在GUI中每帧几次...这是每分钟疯狂的分配数量,按小时计算,它超出了屋顶。


解决方案

我认为无论是添加还是从集合中删除都不重要 - 你不能在foreach循环中做到这一点。


我不确定我是否可以给出真正的技术原因,但是与foreach只是语法糖的事实有关一个代码块,(a)通过调用GetEnumerator()获取集合的枚举器,然后(b)使用
MoveNext和Current然后(c)处理枚举器来迭代该枚举器。


为什么在添加/删除条目周围放置忙标志会产生影响?我承认我不理解你的代码(目前还没有实验的位置)。


看起来你正试图避免代价高昂的分配,这很公平,但真正的答案可能是再次考虑你的数据结构,也许只是首先避免使用foreach循环。


如果没有更多关于你的内容的背景,很难知道答案是什么试图实现,但你可以,例如,为你的键保存一个单独的字符串数组到你的字典中,并简单地循环使用while循环。


如果要删除,请调用myDic.Remove(),然后删除(或删除)数组中的条目,同时跟踪循环变量(因为它是一个简单的while循环,而不是foreach,所以你可以控制用作索引的循环变量
你的数组。)


与添加类似。


Context: I'm using Unity3D's OnGUI{} (updates few times per frame, so VERY often).

Iterating through myDic:

foreach (KeyValuePair<string, float[]> keyValuePair in this.myDic)
{
   //great stuff
}


Now, I know that I cannot modify Dictionary while iterating through it... but is it true for all cases? For example, this:

if (!this.myDicBusy)
{
    foreach (KeyValuePair<string, float[]> keyValuePair in this.myDic)
	{
		if (event1)
		{
			this.myDicBusy = true;
			this.myDic.Remove(keyValuePair.Key);
			this.myDicBusy = false;
		}
	}
}

will produce out of sync. Now, I think I understand why the failsafe bool var does not work here (although, more in-depth explanation would be great if anyone willing to summarize), however, adding:

if (!this.myDicBusy)
{
    foreach (KeyValuePair<string, float[]> keyValuePair in this.myDic)
	{
		if (event2)
		{
			this.myDicBusy = true;
			this.myDic.Add(newstuff);
			this.myDicBusy = false;
		}
	}
}

will never cause out of sync. Why is that so?

P.S. Yes, I know, if I want to modify that type of dictionary while "iterating" through it I can just create a new list of myDic.Keys and iterate, but that's is precisely the thing I want to avoid - creating each new List<> few times per frame in GUI... that's insane amount of allocations per minute, calculate by hour and it goes beyond the roof.

解决方案

I didn't think it mattered whether you are adding or removing from a collection - you just can't do it in a foreach loop.

I'm not sure I can give the real technical reason, but something to do with the fact that foreach is just syntactic sugar for a code block that (a) gets an enumerator for a collection by calling GetEnumerator() then (b) iterates around that enumerator using MoveNext and Current then (c) disposing of the enumerator.

Why would putting busy flags around the adding/removing of entries make a difference? I admit I don't understand your code there (and not in a position at the moment to experiment).

It looks like you are trying to avoid costly allocations, which is fair enough, but the real answer may be to think again about your data structures and perhaps simply avoid foreach loops in the first place.

It's hard to know what the answer is without more context of what you are trying to achieve, but you could, for example, keep a separate array of strings for your keys into your dictionary and simply loop around that with a while loop.

If you want to remove you call myDic.Remove(), then remove (or blank out) that entry in your array as well while keeping track of your loop variable (because its a simple while loop, not a foreach, so you can control the loop variable used as an index into your array).

Similarly with adding.


这篇关于在迭代过程中修改字典(不,不是同一个问题)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆