简体   繁体   English

使用Linq从具有特定属性的树中获取所有对象

[英]Get all objects from a tree with a particular property using Linq

I have a class structure which looks like: 我有一个类似的类结构:

class TestResults {
   public bool IsSuccess;
   public bool IsFailure;

   public IList<TestResults> SubTestResults;
}

So, a test has multiple subtests, and the above captures the results. 因此,一个测试有多个子测试,以上内容捕获了结果。

I want to find all of the TestResults which have IsFailure = true. 我想找到所有具有IsFailure = true的TestResults。

Starting with: 从...开始:

var failures = from result in results
               where result.IsFailure
               select result;

This gives me the top level results which have IsFailure=true, but I want to get all of the tests, and subtests, which have IsFailure=true, and have all of these in list. 这给了我具有IsFailure = true的顶级结果,但是我想获得所有具有IsFailure = true的测试和子测试,并将所有这些和子项都列在列表中。 Is there a linq query that can do this, or should I be using old-fashioned loops? 是否有一个linq查询可以做到这一点,还是应该使用老式循环?

Update: I should say the my usage of these classes means the tree is only 2-deep (structure of the classes is not under my control). 更新:我应该说我对这些类的用法意味着树只有2个深度(类的结构不在我的控制之下)。

So I have: 所以我有:

Test1 - SubTest11
        SubTest12
        SubTest13

Test2 - SubTest21
        SubTest22

Test3 - SubTest31
        SubTest32
        SubTest33
        SubTest34

I need all those subtests which have IsFailure = true. 我需要所有具有IsFailure = true的子测试。

if it is only two levels (ie subtests can't have subtests) then you can do this: 如果只有两个级别(即子测试不能有子测试),则可以执行以下操作:

var failures = results.Union(results.SelectMany(r => r.SubTestResults))
                      .Where(r => r.IsFailure);

This takes the list of results and unions it with the list of all the results children. 这将获取结果列表,并将其与所有结果子级列表合并。

if you can have an arbitrary depth of subtests then you will need something more complicated, so we first define a helper function for the recursion. 如果您可以具有任意深度的子测试,那么您将需要更复杂的东西,因此我们首先为递归定义一个辅助函数。

IEnumerable<TestResults> AllResults(IEnumerable<TestResults> results)
{
    foreach(var tr in results)
    {
        yield return tr;
        foreach(var sr in AllResults(tr.SubTests))
            yield return sr;
    }
}

now we use it and do our filter 现在我们使用它并进行过滤

var failures = from result in AllResults(results)
               where result.IsFailure
               select results;

this should do the trick. 这应该可以解决问题。 however my implementation of AllResults above is not particularly efficient (see Wes Dyers blog for details ) so you really would want to do the typical recursive to iterative conversion on AllResults. 但是,我上面的AllResults的实现不是特别有效( 有关详细信息,请参见Wes Dyers博客 ),因此您确实希望对AllResults执行典型的递归到迭代转换。

IEnumerable<TestResults> AllResults(IEnumerable<TestResults> results)
{
    var queued = new Queue<TestResult>(results); 
    while(queued.Count > 0)
    {
        var tr = queued.Dequeue();
        yield return tr;
        foreach(var sr in tr.SubTests)
            queued.Enqueue(sr);
    }
}

note that you still should add various null checks for completeness 请注意,您仍应添加各种null检查以确保完整性

You need a recursive expression to do that, so given this: 您需要一个递归表达式来执行此操作,因此请执行以下操作:

Func<TestResult, IEnumerable<TestResult>> func = null;
func = r => r.Tests == null
            ? Enumerable.Empty<TestResult>()
            : r.Tests.Where(t => t.IsFailure)
                     .Union(r.Tests.SelectMany(r2 => func(r2)));

var failures = func(tree);

The only thing you need to do, is include the root item if it has failed. 您唯一需要做的就是在失败时包括根项目。 You'll hopefully notice the statement is split between declaration and assignment, this is because a compiler error will occur if you try and assign a recursive delegate straight at the declaration. 希望您会注意到该语句在声明和赋值之间分开,这是因为如果您尝试直接在声明中分配递归委托,则会发生编译器错误。

Try this: 尝试这个:

var failures = from result in results
               where result.GetType().GetProperty("IsFailure") != null
               select result;

Alternatively, have your test classes inherit from a common base class, for example TestBase, and then write your query like this: 或者,让您的测试类继承自通用基类(例如TestBase),然后像这样编写查询:

var failures = from result in results
               where result is TestBase
               select result;

EDIT: Hmm, I think I misunderstood your question on the first read-through 编辑:嗯,我想我在第一次通读时就误解了你的问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用LINQ,获取包含特定属性值的对象的列表 - Using LINQ, get a list of objects that contain a particular property value 使用LINQ从对象列表中获取一组特定的对象 - using LINQ to get a particular set of objects from a list of objects LINQ:如何使用LINQ查找Array属性包含特定值的所有对象 - LINQ: How do I find all the objects whose Array property contains a particular value using LINQ 使用LINQ从列表中获取具有特定属性最大值的对象 - Get the objects with the maximum value for a specific property from a list using LINQ LINQ:从传入的IEnumerable中获取具有匹配字符串属性的所有对象 <string> 以表演的方式 - LINQ: Get all objects with a matching string property from an incoming IEnumerable<string> in a performant way 使用Linq到C#获取特定的属性值 - get a particular property value using Linq to C# Linq:基于属性获取我的所有子对象 - Linq: get my all my sub objects base on property 使用LINQ从对象列表中隔离特定对象 - Using LINQ to isolate a particular object from a list of objects 如何使用LINQ从树中的所有节点获取列表? - How can I get a List from all nodes in a tree using LINQ? 使用LINQ为集合中的所有对象的属性赋值的最佳方法 - Best way to assign a value to a property of all objects in a collection using LINQ
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM