使用递归从 IDictionary 中删除项目
有人有更巧妙的方法来做到这一点吗? 看起来应该比这更容易,但我有心理障碍。 基本上我需要从字典中删除项目并递归到也是字典的项目的值。
private void RemoveNotPermittedItems(ActionDictionary menu)
{
var keysToRemove = new List<string>();
foreach (var item in menu)
{
if (!GetIsPermitted(item.Value.Call))
{
keysToRemove.Add(item.Key);
}
else if (item.Value is ActionDictionary)
{
RemoveNotPermittedItems((ActionDictionary)item.Value);
if (((ActionDictionary)item.Value).Count == 0)
{
keysToRemove.Add(item.Key);
}
}
}
foreach (var key in (from item in menu where keysToRemove.Contains(item.Key) select item.Key).ToArray())
{
menu.Remove(key);
}
}
动作字典是这样的:
public class ActionDictionary : Dictionary<string, IActionItem>, IActionItem
Anybody have a slicker way to do this? Seems like it should be easier than this, but I'm having a mental block. Basically I need to remove items from an dictionary and recurse into the values of the items that are also dictionaries.
private void RemoveNotPermittedItems(ActionDictionary menu)
{
var keysToRemove = new List<string>();
foreach (var item in menu)
{
if (!GetIsPermitted(item.Value.Call))
{
keysToRemove.Add(item.Key);
}
else if (item.Value is ActionDictionary)
{
RemoveNotPermittedItems((ActionDictionary)item.Value);
if (((ActionDictionary)item.Value).Count == 0)
{
keysToRemove.Add(item.Key);
}
}
}
foreach (var key in (from item in menu where keysToRemove.Contains(item.Key) select item.Key).ToArray())
{
menu.Remove(key);
}
}
Action dictionary is like this:
public class ActionDictionary : Dictionary<string, IActionItem>, IActionItem
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
如果您反向迭代字典(从“menu.Count - 1”到零),您实际上不需要收集键并再次迭代它们。 当然,如果您开始删除某些内容,则按正向顺序迭代会产生变异的集合异常。
我不知道 ActionDictionary 是什么,所以我无法测试您的确切场景,但这里有一个仅使用
Dictionary
的示例。我还颠倒了“if”语句,但这只是一个假设,即您希望在调用对项目的值进行操作的方法之前进行类型检查...假设“GetIsPermission”始终返回 TRUE,那么无论哪种方式都可以工作行动词典。
希望这可以帮助。
You don't really need to collect the keys and iterate them again if you iterate the dictionary in reverse (from 'menu.Count - 1' to zero). Iterating in forward order will, of course, yield mutated collection exceptions if you start removing things.
I don't know what an ActionDictionary is, so I couldn't test your exact scenario, but here's an example using just
Dictionary<string,object>
.I also reversed the 'if' statement, but that was just an assumption that you'd want to do type checking before calling a method to act on the item's value...it will work either way assuming 'GetIsPermitted' always returns TRUE for ActionDictionary.
Hope this helps.
虽然 foreach 和 GetEnumerator 失败,但 for 循环可以工作,
但 ElementAt() 是 .NET 3.5 的一项功能。
While foreach and GetEnumerator fails, a for-loop works,
But ElementAt() is a .NET 3.5 feature.
首先,您的
foreach
循环比它需要的要复杂得多。 就这样做:我有点惊讶
Dictionary
没有RemoveAll
方法,但它看起来不像有......To start with, your
foreach
loop is way more complicated than it needs to be. Just do:I'm slightly surprised that
Dictionary
doesn't have aRemoveAll
method but it doesn't look like it does...选项 1:字典仍然是集合。 迭代 menu.Values。
您可以迭代 menu.Values 并在迭代时删除它们。 这些值不会按任何排序顺序出现(这应该适合您的情况)。 您可能需要使用 for 循环并调整索引,而不是使用 foreach - 如果您在迭代时修改集合,枚举器将引发异常。
(周一,我将在我的开发机器上尝试添加代码)
选项 2:创建自定义迭代器。
从 Winforms 中的 ListBox SelectedItems 返回的一些集合并不真正包含该集合,它们提供了底层集合的包装。 有点像 WPF 中的 CollectionViewSource。 ReadOnlyCollection 也做了类似的事情。
创建一个类,可以将嵌套字典“扁平化”为可以枚举它们的类,就像它们是单个集合一样。 实现一个删除函数,看起来像是从集合中删除一个项目,但实际上是从当前字典中删除。
Option 1: A Dictionary is still a Collection. Iterate over menu.Values.
You can iterate over menu.Values and remove them as you iterate. The values won't come in any sorted order (which should be fine for your case). You may need to use a for loop and adjust the index rather than using foreach - the enumerator will throw an exception if you modify the collection while iterating.
(I'll try to add the code when I'm on my dev machine Mon)
Option 2: Create a custom iterator.
Some collections returned from ListBox SelectedItems in Winforms don't really contain the collection, they provide a wrapper around the underlying collection. Kind of like CollectionViewSource in WPF. ReadOnlyCollection does something similar too.
Create a class that can "flatten" your nested dictionaries into something that can enumerate over them like they are a single collection. Implement a delete function that looks like it removes an item from the collection, but really removes from the current dictionary.
在我的观点中,您可以定义自己的从
KeyValuePair<...>
派生的泛型类,TKey 和 TValue 都将是List
并且您可以使用新的RemoveRange()
或RemoveAll( 中
方法在您的派生类中删除您想要的项目。List
的RemoveAll
或RemoveRange
)In My Opinion, you can define your own generic class deriving from the
KeyValuePair<...>
both TKey and TValue will beList<T>
and you can use theRemoveAll
or theRemoveRange
of theList<T>
in a newRemoveRange()
orRemoveAll()
method in your derived class to Remove the items you want.我知道您可能已经找到了很好的解决方案,但只是出于“圆滑”的原因,如果您可以将方法签名修改为(我知道它可能不适合您的场景):
而且我可以看到几种方法,您可以使用您的方法带有过滤项目的字典,无需修改并具体化新字典。
I know you probably found good solution already, but just for the reason of 'slickness' if you could modify your method signatures to (I know it may not be appropriate in your scenario):
And I can see couple ways where you can use your dictionary with filtered items without modification and materializing new dictionaries.
它并没有那么复杂,但是一些惯用的改变使它变得更短并且更容易看:
It's not much less complicated, but some idiomatic changes make it a bit shorter and easier on the eyes:
将
keysToRemove
的类型更改为HashSet
,您将获得 O(1)Contains
方法。 对于List
,它的复杂度为 O(n),正如您可能猜到的那样,速度较慢。Change the type of the
keysToRemove
toHashSet<string>
and you'll get an O(1)Contains
method. WithList<string>
it's O(n), which is slower as you might guess.明天我在我的 VS 机器上之前尚未测试:o
untested until i'm at my VS machine tomorrow :o
我认为
并且
应该工作得快
I think
And
Should work fast