Linq基于列表值对类进行过滤

时间:2017-07-10 18:56:07

标签: entity-framework linq lambda linq-to-sql linq-to-entities

var filteredStudent = new List<Student>();
string description = "Managing the Course";
foreach (var student in students)
{
    if (student.subjetcs.Any(x => x.Sylabus.Name.Contains("Critical")))
    {
        if (student.subjetcs.Any(x => x.Sylabus.Name.Contains("Critical") &&
                                      description.Contains(x.Description)))
        {
           filteredStudent.Add(student);
        }
    }
    else
    {
        filteredStudent.Add(student);
    }
}

是否可以用单个Linq语句替换所有上述逻辑?

因为我对Linq很感兴趣

3 个答案:

答案 0 :(得分:2)

第一步:简化您的逻辑。第一步,摆脱Name.Contains("Critical")的冗余检查。当你到达那里时,你绝对肯定Name包含“Critical”。

所以标准是 - 如果名称不包含“严重”OR(即,如果符号),则描述匹配。并且,如果你考虑它,这意味着括号中的位(“即,如果......”)变得无关紧要。如果描述匹配,那么我们总是添加学生是否包含“严重”。我们还添加了一个没有“Critical”的那个可以呈现为:

更新:octavioccl指出错误。

var filteredStudent = students
                  .Where(s=>!s.subjects.Any(x => x.Sylabus.Name.Contains("Critical") || 
                            description.Contains(x.Description)))
                  .ToList();

注意:鉴于对上述内容的更新,下半部分可能会比​​上半部分更快,所以我们可能应该对它们进行反转。

var filteredStudent = students
                  .Where(s=>s.subjects
                    .Any(x => 
                        description.Contains(x.Description) ||
                        !x.Sylabus.Name.Contains("Critical"))) 
                  .ToList();

更新(再次) 一夜之间想到这一点,我意识到这不起作用。那么,让我们再试一次......   - 我们希望所有学生除了那些主题包含“严重”的学生,除非该课程的描述匹配。 (重要提示 - 尽管有一种名为Except()的Linq方法不是我们想要的 - 我们实际上想要不在哪里。 所以,首先要做的是:

var filteredStudent = students
              .Where(s=>!s.subjects.Any(x => 
                          x.Sylabus.Name.Contains("Critical")
                          ?  !description.Contains(x.Description)
                          : false)
              .ToList();

所以,这里最内部的lambda(x => ...)是一个测试,如果一个特定的主题是拒绝学生的理由。如果它不包含“严重”,则可以(通过最后的false)。如果是,则如果描述不匹配则拒绝。

然而,从这里我们可以缩短它。考虑一下我们刚才所说的,如果第一次测试是假的,那么整件事就是假的。如果第一次测试是真的,那么基于第二次测试,整个表达式是真的还是假的 - 这正是“短路和”的定义,因此:

var filteredStudent = students
              .Where(s=>!s.subjects.Any(x => 
                          x.Sylabus.Name.Contains("Critical")
                          &&  !description.Contains(x.Description))
              .ToList();

请阅读我们得到的结论,“除了那些正在接受Sylabus名称包含”严重“但没有相应描述的主题的学生外,我们会接受所有学生。

答案 1 :(得分:1)

添加到结果列表的条件如下:

  

Sylabus.Name不包含&#34;严重&#34;或Sylabus.Name包含&#34;严重&#34; description包含Description

这可以编码为单个Where条件。

答案 2 :(得分:0)

我不明白为什么要重复这个条件:student.subjects.Any(x => x.Syllabus.Name.Contains("Critical")),然后使用相同的结果:filteredStudent.Add(student)

如果要添加列表中的所有项目,请执行以下操作:

    students.ToList().ForEach(s => filteredStudent.Add(s));

如果要过滤结果,请添加Where

    students.Where(s => s.subjetcs.Any(x => x.Sylabus.Name.Contains("Critical") && description.Contains(x.Description)))
      .ToList().ForEach(s => filteredStudent.Add(s));

也许你想要这样的东西:

    var list = new List<Stundent>();
    list.AddRange(studnets.Where(s => s.subjetcs.Any(x => x.Sylabus.Name.Contains("Critical") && description.Contains(x.Description)));
    list.AddRange(studnets.Where(s => s.subjetcs.All(x => !x.Sylabus.Name.Contains("Critical")));
    list.ForEach(x => filteredStudent.Add(x));

OR:

    students.Where(s => s.subjetcs.Any(x => x.Sylabus.Name.Contains("Critical") && description.Contains(x.Description)) || s.subjetcs.All(x => !x.Sylabus.Name.Contains("Critical"))
      .ToList().ForEach(s => filteredStudent.Add(s));