【发布时间】:2011-01-09 01:16:53
【问题描述】:
我有一个 C# 字典 Dictionary<Guid, MyObject>,需要根据 MyObject 的属性进行过滤。
例如,我想从字典中删除MyObject.BooleanProperty = false 所在的所有记录。实现这一目标的最佳方法是什么?
【问题讨论】:
标签: c# generics dictionary filtering
我有一个 C# 字典 Dictionary<Guid, MyObject>,需要根据 MyObject 的属性进行过滤。
例如,我想从字典中删除MyObject.BooleanProperty = false 所在的所有记录。实现这一目标的最佳方法是什么?
【问题讨论】:
标签: c# generics dictionary filtering
如果您不关心创建包含所需项目的新字典并丢弃旧字典,只需尝试:
dic = dic.Where(i => i.Value.BooleanProperty)
.ToDictionary(i => i.Key, i => i.Value);
如果您无法创建新字典并且由于某种原因需要更改旧字典(例如当它被外部引用并且您无法更新所有引用时:
foreach (var item in dic.Where(item => !item.Value.BooleanProperty).ToList())
dic.Remove(item.Key);
请注意,ToList 在此处是必需的,因为您正在修改基础集合。如果您更改基础集合,则在其上工作以查询值的枚举器将无法使用,并将在下一次循环迭代中引发异常。 ToList 在更改字典之前缓存值。
【讨论】:
由于 Dictionary 实现了IEnumerable<KeyValuePair<Key, Value>>,所以你可以直接使用Where:
var matches = dictionary.Where(kvp => !kvp.Value.BooleanProperty);
如果需要,要重新创建一个新字典,请使用ToDictionary 方法。
【讨论】:
您可以简单地使用Linq where 子句:
var filtered = from kvp in myDictionary
where !kvp.Value.BooleanProperty
select kvp
【讨论】:
public static Dictionary<TKey, TValue> Where<TKey, TValue>(this Dictionary<TKey, TValue> instance, Func<KeyValuePair<TKey, TValue>, bool> predicate)
{
return Enumerable.Where(instance, predicate)
.ToDictionary(item => item.Key, item => item.Value);
}
【讨论】:
这是一个通用解决方案,不仅适用于值的布尔属性。
方法
提醒:扩展方法必须放在静态类中。不要忘记源文件顶部的using System.Linq; 语句。
/// <summary>
/// Creates a filtered copy of this dictionary, using the given predicate.
/// </summary>
public static Dictionary<K, V> Filter<K, V>(this Dictionary<K, V> dict,
Predicate<KeyValuePair<K, V>> pred) {
return dict.Where(it => pred(it)).ToDictionary(it => it.Key, it => it.Value);
}
用法
例子:
var onlyWithPositiveValues = allNumbers.Filter(it => it.Value > 0);
【讨论】:
我为我的项目添加了以下扩展方法,允许您过滤 IDictionary。
public static IDictionary<keyType, valType> KeepWhen<keyType, valType>(
this IDictionary<keyType, valType> dict,
Predicate<valType> predicate
) {
return dict.Aggregate(
new Dictionary<keyType, valType>(),
(result, keyValPair) =>
{
var key = keyValPair.Key;
var val = keyValPair.Value;
if (predicate(val))
result.Add(key, val);
return result;
}
);
}
用法:
IDictionary<int, Person> oldPeople = personIdToPerson.KeepWhen(p => p.age > 29);
【讨论】: