使用linq或lambda去除外部foreach循环并确保没有重复项添加到列表中

时间:2013-06-19 15:06:21

标签: c# linq lambda

我对这个问题有2个部分:

  1. 有没有办法摆脱外循环

    List<Document> newDocuments = new List<Document>();
    foreach (DocumentDetail documentDetail in documentDetails)
    {
        newDocuments.AddRange(documents.FindAll(d => d.Extension.ToUpperInvariant() == documentDetail.Extension.ToUpperInvariant()));
    }
    
  2. 正如你从上面所看到的,我只是处理“扩展”,即使我最终保持我的外部foreach循环,我仍然想检查所有其他属性(即描述等)。 ..)所以我可能最终会对内部部分进行多次调用,最终会看起来像这样,假设我现在正在检查描述

    newDocuments.AddRange(documents.FindAll(d => d.Description.ToUpperInvariant() == documentDetail.Description.ToUpperInvariant()));
    
  3. 上述问题是,如果文档恰好具有.pdf扩展名,然后匹配描述,我最终可能会出现重复文档。

    如何确保不添加重复文档。我可以在linq查询(或lambda?)中添加一些东西。就唯一性而言,虽然不明确,但现在我可以访问“documentno”,这对于“文档”列表中的所有文档都是唯一的。

    如果您知道某一部分的答案,请告诉我。

    赞赏!

    被修改

    这个怎么样?它确实有效,但我不确定这是写这个的正确方法吗?

    List<Document> newDocs = (from documentDetail in documentDetails
                              from document in documents
                              where document.Extension.ToUpperInvariant() == documentDetail.Extension.ToUpperInvariant()
                               select document).Distinct().ToList();
    

    我最好只是坚持使用foreach循环吗?

    使用上面的内容,如果我想根据文档列表检查DocumentDetails列表中的多个属性,我最终会得到类似的内容:

            List<Document> newDocuments = null;
    
            if (documentDetails.FindAll(dd => (dd.Extension != null || !string.IsNullOrEmpty(dd.Extension))).Count > 0)
            {
                newDocuments = (from documentDetail in documentDetails
                                from document in documents
                                where document.Extension.ToUpperInvariant() == documentDetail.Extension.ToUpperInvariant()
                                select document).Distinct().ToList();
            }
    
            if (documentDetails.FindAll(dd => (dd.Description != null || !string.IsNullOrEmpty(dd.Description))).Count > 0)
            {
                newDocuments = (from documentDetail in documentDetails
                                from document in documents
                                where document.Description.ToUpperInvariant() == documentDetail.Description.ToUpperInvariant()
                                select document).Distinct().ToList();
            }
    

    虽然我仍然希望有人确认我写这个的方式是正确的,但我仍然留下如何追加结果然后删除所有重复项。我想当一切都完成后,我可以应用Distinct,但我仍然留下“附加”问题。那我该怎么办?

    感谢。

3 个答案:

答案 0 :(得分:1)

您可以在处理列表之前删除任何重复项:

List<Document> newDocuments = new List<Document>();
List<Document> distinctItems = newDocuments .Distinct();
foreach (DocumentDetail documentDetail in documentDetails)
{
    newDocuments.AddRange(documents.FindAll(d => d.Extension.ToUpperInvariant() == documentDetail.Extension.ToUpperInvariant()));
}

答案 1 :(得分:1)

我会看到类似这样的事情:尚未测试 - 类定义会有所帮助!

var extensions = documentDetail.Select(d => d.Extension.ToUpperInvariant()).ToList();
var newDocuments = documents.Where(d => extensions.Contains(d.Extension.ToUpperInvariant())).ToList();

答案 2 :(得分:0)

您在这里逻辑上做的是Join

var newDocuments = documentDetails.Join(documents,
        documentDetail => documentDetail.Extension,
        document => document.Extension,
        (documentDetail, document) => document,
        StringComparer.InvariantCultureIgnoreCase)
    .Distinct();

(这可以在查询语法中完成,而不是方法语法,但是你不能提供字符串比较器,它允许你比较字符串而不需要转换它们的情况。这是执行不区分大小写的适当方法比较)。

从功能的角度来看,此代码与您的第一个编辑版本完全相同,只是它的很多效率更高。您正在做的是将每个单个文档与每个单个详细记录配对,然后在假设每个列表中的项目具有“密钥”并且您希望这些密钥匹配的项目的情况下过滤掉您需要的那些文档。这是一个常见的操作,它有自己的特殊操作符(Join)。也可以比代码中更大程度地优化此特定情况。 Join运算符只能创建它需要的那些对;它不需要匹配不属于一起的 lot 项目,只是稍后将它们抛出。