ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

c# – 如何制作流式LINQ表达式,以提供已过滤的项目以及过滤的项目?

2019-06-13 00:52:42  阅读:172  来源: 互联网

标签:c enumeration linq out


我正在将Excel电子表格转换为“元素”列表(这是一个域名术语).在此转换期间,我需要跳过标题行并抛出无法转换的格式错误的行.

有趣的来了.我需要捕获那些格式错误的记录,以便我可以报告它们.我构建了一个疯狂的LINQ语句(如下).这些扩展方法隐藏了OpenXml库中类型的凌乱LINQ操作.

var elements = sheet
    .Rows()                          <-- BEGIN sheet data transform
    .SkipColumnHeaders()
    .ToRowLookup()
    .ToCellLookup()
    .SkipEmptyRows()                 <-- END sheet data transform
    .ToElements(strings)             <-- BEGIN domain transform
    .RemoveBadRecords(out discard)
    .OrderByCompositeKey();

有趣的部分从ToElements开始,在那里我将行查找转换为我的域对象列表(详细信息:它称为ElementRow,后来转换为Element).只使用一个键(Excel行索引)创建错误记录,并且与真实元素相比是唯一可识别的.

public static IEnumerable<ElementRow> ToElements(this IEnumerable<KeyValuePair<UInt32Value, Cell[]>> map)
{
    return map.Select(pair =>
    {
        try
        {
            return ElementRow.FromCells(pair.Key, pair.Value);
        }
        catch (Exception)
        {
            return ElementRow.BadRecord(pair.Key);
        }
    });
}

然后,我想删除那些不良记录(在过滤之前更容易收集所有这些记录).那个方法是RemoveBadRecords,就像这样开始……

public static IEnumerable<ElementRow> RemoveBadRecords(this IEnumerable<ElementRow> elements)
{
    return elements.Where(el => el.FormatId != 0);
}

但是,我需要报告丢弃的元素!而且我不想通过报告来混淆我的变换扩展方法.所以,我去了out参数(考虑到在匿名块中使用out参数的the difficulties)

public static IEnumerable<ElementRow> RemoveBadRecords(this IEnumerable<ElementRow> elements, out List<ElementRow> discard)
{
    var temp = new List<ElementRow>();
    var filtered = elements.Where(el =>
    {
        if (el.FormatId == 0) temp.Add(el);
        return el.FormatId != 0;
    });

    discard = temp;
    return filtered;
}

哦,瞧!我以为我是铁杆,并且会一次性工作……

var discard = new List<ElementRow>();
var elements = data
    /* snipped long LINQ statement */
    .RemoveBadRecords(out discard)
    /* snipped long LINQ statement */

discard.ForEach(el => failures.Add(el));

foreach(var el in elements) 
{ 
    /* do more work, maybe add more failures */ 
}

return new Result(elements, failures);

但是,当我循环播放它时,我的丢弃列表中没有任何内容!我逐步完成了代码并意识到我成功创建了一个完全流式LINQ语句.

>临时列表已创建
>已分配Where过滤器(但尚未运行)
>并且分配了丢弃清单
>然后返回流媒体的东西

迭代丢弃时,它不包含任何元素,因为元素尚未迭代.

有没有办法使用我构建的东西来解决这个问题?我是否必须在错误记录过滤器之前或期间强制重复数据?我错过了另一种建筑吗?

一些评论

Jon提到了任务/正在/正在发生.我只是没有等待它.如果我在元素迭代后检查丢弃的内容,它实际上已经满了!所以,我实际上没有任务分配问题.除非我接受Jon关于LINQ语句中哪些好/坏的建议.

解决方法:

When the statement was actually iterated, the Where clause ran and temp filled up, but discard was never assigned again!

它不需要再次分配 – 将填充将在调用代码中分配给丢弃的现有列表.

但是,我强烈建议不要采用这种方法.在这里使用out参数确实违背了LINQ的精神. (如果你两次迭代你的结果,你最终会得到一个包含所有坏元素两次的列表.Ick!)

我建议在删除坏记录之前实现查询 – 然后你可以运行单独的查询:

var allElements = sheet
    .Rows()
    .SkipColumnHeaders()
    .ToRowLookup()
    .ToCellLookup()
    .SkipEmptyRows()
    .ToElements(strings) 
    .ToList();

var goodElements = allElements.Where(el => el.FormatId != 0)
                              .OrderByCompositeKey();

var badElements = allElements.Where(el => el.FormatId == 0);

通过在List<>中实现查询,您只需按ToRowLookup,ToCellLookup等处理每一行.它确实意味着您需要有足够的内存来保存所有元素,当然.还有其他方法(例如对每个坏元素进行操作,同时对其进行过滤)但它们仍然可能最终变得相当脆弱.

编辑:Servy提到的另一个选择是使用ToLookup,它将实现并分组:

var lookup = sheet
    .Rows()
    .SkipColumnHeaders()
    .ToRowLookup()
    .ToCellLookup()
    .SkipEmptyRows()
    .ToElements(strings) 
    .OrderByCompositeKey()
    .ToLookup(el => el.FormatId == 0);

然后你可以使用:

foreach (var goodElement in lookup[false])
{
    ...
}

foreach (var badElement in lookup[true])
{
    ...
}

请注意,这会对所有元素执行排序,无论好坏.另一种方法是从原始查询中删除顺序并使用:

foreach (var goodElement in lookup[false].OrderByCompositeKey())
{
    ...
}

我个人并不喜欢用真/假分组 – 感觉有点滥用通常意味着基于密钥的查找 – 但它肯定会起作用.

标签:c,enumeration,linq,out
来源: https://codeday.me/bug/20190613/1229547.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有