根据字典值中的列表类型进行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<> ?

谢谢。

根据字典值中的列表类型进行LINQ筛选

我想你需要这样的东西:

IEnumberable<MySubType> query = dataItemMap[identCode].OfType<MySubType>();

这将获得具有给定键的列表,然后对其进行筛选,只返回MySubType元素。

编辑:我一直在关注为什么现有的解决方案不起作用(以及"我已经为每个元素提供了一个值列表,并且我想使其扁平化"的一般问题),而不是后退一步。正如Andy的答案所示,您几乎肯定应该使用它是字典的事实-将它从O(n)操作转换为O(1):)

两个事项:

  • 当前代码将始终identCode和字典键执行顺序的,不区分区域性的比较;使用字典查找将使用构造它的比较器。
  • 如果identCode在字典中没有找到,当前代码将返回一个空序列;字典索引器将抛出异常。如果你想避免这种情况,可以使用TryGetValue

请注意,如果您知道最后选择的所有元素实际上都是正确类型的,则可能使用CastOfType更好:

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>());