linq 如何从集合中获取所有嵌套项?

gojuced7  于 2022-12-06  发布在  其他
关注(0)|答案(5)|浏览(158)

我有一个项目集合,一个项目可以有另一个项目,另一个项目可以有另一个项目,如此类推。
我不知道有多少层的嵌套项可以有项。嵌套项的层可以在运行时定义。

class Person
{
    Person person;
    public Person(Person _nestedPerson)
    {
        person = _nestedPerson;
    }

    public bool IsSelectedPerson { get; set; }
    public string Name { get; set; }
}

以及如何嵌套项(Person):

IList<Person> list = new List<Person>();            
for (int startIndex = 0; startIndex < 5; startIndex++)
{
   list.Add(new Person(new Person(new Person(new Person(null) { Name="Bill", 
        IsSelectedPerson=true})) { Name = "Jessy", IsSelectedPerson = false }) 
        { Name = "Bond", IsSelectedPerson =true});//3 nested persons
   list.Add(new Person(new Person(null) { Name = "Kendell", 
        IsSelectedPerson = true }) { Name="Rosy", IsSelectedPerson=true});//2 nested persons
   //The next time it can be just one person without nested item(person). I do not know how many items(persons) will be nested
   //list.Add(new Person(null) { Name="Rosy", IsSelectedPerson=true});
}
  • 我的目标是获取所有对象(无重复项)的人员(Person),这些人员是IsSelectedPerson=true?*

我玩过Select()

var ee = list.Select(x=>x.IsSelectedFacet==true);//comparison should be done here

但它不是我想要的,它只接受bool值。

更新日期:
我期望的结果应该是有一个Person的对象,并且具有唯一的名称。不管有多少个具有相同名称的对象。我只想取一个对象。抱歉造成误解。它应该是这样的:

db2dz4w8

db2dz4w81#

您可以创建一个helper方法来展开所有嵌套对象

IEnumerable<Person> UnwrapPerson(Person p)
    {
        List<Person> list = new List<Person>();
        list.Add(p);
        if (p.person != null)
            list.AddRange(UnwrapPerson(p.person));

        return list;
    }

或者,如果Person类只有一个嵌套对象(Person person;),则可以使用yield构造来代替递归

static IEnumerable<Person> UnwrapPerson(Person p)
    {
        yield return p;
        while (p.person != null)
        {
            p = p.person;
            yield return p;
        }
    }

为了删除所有重复的人员,例如具有相同名称的人员,您应该实现IEqualityComparer<Person>,然后使用Distinct方法。

class Comparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return string.Equals(x.Name, y.Name);
    }

    public int GetHashCode(Person obj)
    {
        string name = obj.Name;
        int hash = 7;
        for (int i = 0; i < name.Length; i++)
        {
            hash = hash * 31 + name[i];
        }

        return hash;
    }
}

因此,最终查询应类似于:

list.SelectMany(p => UnwrapPerson(p))
     .Where(x => x.IsSelectedPerson == true)
     .Distinct(new Comparer())
mrwjdhj3

mrwjdhj32#

下面是另一种生成项目列表的方法:

IEnumerable<Person> GetIsSelectedPerson(Person p)
{
    Person temp = p;
    while (temp != null)
    {
        if (temp.IsSelectedPerson)
        {
            yield return temp;
        }
        temp = temp.person;
    }           
}

用法:

IEnumerable<Person> Result = GetIsSelectedPerson(rootPerson)
5cg8jx4n

5cg8jx4n3#

我将使用某种带有递归的访问模式来访问所有嵌套的Persons

class Person
{
   public static List<Person> selectedPersons;
   Person person;
   public Person(Person _nestedPerson)
   {
       if(selectedPersons == null)
         selectedPersons = new List<Person>();
       person = _nestedPerson;
   }

   public bool IsSelectedPerson { get; set; }
   public string Name { get; set; }

   public void Visit()
   {
       if(this.IsSelectedPerson)
         selectedPersons.Add(this);
       if(this.person != null)
         this.person.Visit();
   }
}
pvabu6sv

pvabu6sv4#

由于你不知道链中的人的级别,最好的方法是使用递归。两个简单的解决方案(假设你在Person类上添加方法)
1.创建一个接收列表的方法,这样就可以在递归调用中填充它:列表完成List =新建List();列表[0]。获取完整列表(完整列表);列表[1]。获取完整列表(完整列表);

public void GetCompleteList(List<Person> personsList)
{
    personsList.Add(this);
    if (person != null)
    {
        person.GetCompleteList(personsList);
    }
}

1.相同,无参数

List<Person> completeList = new List<Person>();
completeList.AddRange(list[0].GetCompleteList());
completeList.AddRange(list[1].GetCompleteList());

// Another way: with linq
var myPersons  list.SelectMany(m => m.GetCompleteList());

public List<Person> GetCompleteList()
 {
     List<Person> returnList = new List<Person>();
     returnList.Add(this);
     if (person != null)
     {
         returnList.AddRange(person.GetCompleteList());
     }
     return returnList;
 }
bz4sfanl

bz4sfanl5#

这样做是为了把人压扁,

Func<Person, IEnumerable<Person>> flattener = null;
flattener = p => new[] { p }
    .Concat(
        p.person == null 
            ? Enumerable.Empty<Person>()
            : (new [] { p.Person }).SelectMany(child => flattener(child)));

所以你能做到,

flattener(person).Where(p => p.IsSelectedPerson);

听完你的话,你可能想要的是,

flattener(person)
   .Where(p => p.IsSelectedPerson)
   .Select(p => p.Name)
   .Distinct();

相关问题