根据字典值中的列表类型进行LINQ筛选
本文关键字:类型 LINQ 筛选 列表 字典 | 更新日期: 2023-09-27 18:02:01
认为这是一个非常基本的问题,但这是我的第一个LINQ查询,我完全卡住了:
我有一个具有字符串键和列表值的字典(见下面的定义),并且想要提取特定类型的列表中的元素,并通过字典键选择列表。
IDictionary<string, IList<MyBaseType>> dataItemMap;
Where MySubType extends MyBaseType.
我的问题是:
string identCode = "foo";
IEnumerable<MySubType> query =
from entry in dataItemMap
where entry.Key == identCode
select entry.Value.OfType<MySubType>();
和错误信息(来自LinqPad):
Cannot implicitly convert type
'System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable<MySubType>>'
to 'System.Collections.Generic.IEnumerable<MySubType>'.
An explicit conversion exists (are you missing a cast?)
问题显然在entry.Value.OfType<>中,但我如何指定列表元素?我正在寻找类似entry.Value.Items.OfType<> ?
谢谢。
我想你需要这样的东西:
IEnumberable<MySubType> query = dataItemMap[identCode].OfType<MySubType>();
这将获得具有给定键的列表,然后对其进行筛选,只返回MySubType元素。
编辑:我一直在关注为什么现有的解决方案不起作用(以及"我已经为每个元素提供了一个值列表,并且我想使其扁平化"的一般问题),而不是后退一步。正如Andy的答案所示,您几乎肯定应该使用它是字典的事实-将它从O(n)操作转换为O(1):)
两个事项:
- 当前代码将始终与
identCode
和字典键执行顺序的,不区分区域性的比较;使用字典查找将使用构造它的比较器。 - 如果
identCode
在字典中没有找到,当前代码将返回一个空序列;字典索引器将抛出异常。如果你想避免这种情况,可以使用TryGetValue
。
请注意,如果您知道最后选择的所有元素实际上都是正确类型的,则可能使用Cast
比OfType
更好:
var query = dataItemMap[identCode].Cast<MySubType>();
当两者都可以工作时,我通常更喜欢Cast
而不是OfType
,因为这意味着如果我对序列中数据的假设证明是不正确的,我将以异常而不是无声地丢失数据来发现它。
注意Cast
也会返回null
元素,而OfType
不会。
不,问题不在于使用OfType<>
-这是你已经结束了序列序列,但你试图将其分配给单个序列。
要么更改返回类型,要么使用另一个from
子句来平坦化结果:
IEnumerable<MySubType> query = from entry in dataItemMap
where entry.Key == identCode
from value in entry.Value.OfType<MySubType>()
select value;
我很想直接使用扩展方法:
var query = dataItemMap.Where(e => e.Key == identCode)
.SelectMany(e => e.Value.OfType<MySubType>());