0

我有这样的课

class Person {
 private Id;
 private parentId;
 private Name;
}

我有一个看起来像这样的人的列表:

List<Person> persons = new List<Person>();
persons.Add(new Person{Id =1, Name = "Andy", parentId = 0});
persons.Add(new Person{Id =2, Name = "Sandy", parentId = 0});
persons.Add(new Person{Id =3, Name = "Carter", parentId = 9});
persons.Add(new Person{Id =4, Name = "Mark", parentId = 9});
persons.Add(new Person{Id =5, Name = "Martin", parentId = 99});
persons.Add(new Person{Id =6, Name = "Matt", parentId = 99});

我想要的是:

persons.Add(new Person{Id =1, Name = "Andy", parentId = 0});
persons.Add(new Person{Id =2, Name = "Sandy", parentId = 0});
persons.Add(new Person{Id =3, Name = "Carter", parentId = 9});
persons.Add(new Person{Id =6, Name = "Matt", parentId = 99});

我想保留所有 parentId 为 0 的人,但只从多个分组对象中选择一个。

谢谢

4

4 回答 4

9

这应该可以解决问题(似乎来自测试)。

var rootItems = persons.Where(x=>x.parentId==0);
var childItems = persons.Where(x=>x.parentId!=0).GroupBy(x=>x.parentId).Select(x=>x.First());
var requiredItems = rootItems.Concat(childItems);

它基本上分为两部分,第一部分只是获取所有根项。第二个按 parentId 对它们进行分组,然后选择每个组中的第一个项目。如果您想进一步细化选择哪一个,则可以对此进行调整。

附加说明:

作为产生问题准确输出的练习,以下可用于子项:

var childItems = persons.Where(x=>x.parentId!=0)
    .GroupBy(x=>x.parentId)
    .Select(
        x=>x.OrderBy(y=>y.Id%3)
        .First()
);

这显然是从选项中选择的一种有点荒谬的方式,但确实展示了如何通过添加某种排序标准来更改选择的项目。

于 2013-07-09T14:42:33.070 回答
5

要从每个 parentId 分组中获取一个人,只需对该值进行分组,然后从每个组中选择第一个。然后,您可以将其与父 ID 为 0 的人连接。

var query = people.Where(p => p.parentId == 0)
    .Concat(people.Where(p => p.parentId != 0)
        .GroupBy(p => p.parentId)
        .Select(group => group.First()));
于 2013-07-09T14:44:15.197 回答
2

假设您有一个 AllPersons 列表:

var parentsAdded = new HashSet<int>();

foreach(var person in AllPersons)
{
    if(person.parentId == 0 || parentsAdded.Add(person.parentId))
    {
       persons.Add(person);
    }

}
于 2013-07-09T14:42:02.127 回答
1

最简单的方法是使用两个单独的查询parentId == 0第一个来自组合并使用方法的Concat方法。

var results = people.Where(x => x.parentId == 0)
                    .Concat(persons.Where(x => x.parentId != 0)
                                   .GroupBy(x => x.parentId)
                                   .Select(x => x.First()))

但是,它需要两次通过集合。我建议为此编写您自己的扩展方法:

public static class Enumerable
{
    public static IEnumerable<Person> GetFirsts(this IEnumerable<Person> source)
    {
        var set = new HashSet<int>();

        foreach (var person in source)
        {
            if (person.parentId == 0 || set.Add(person.parentId))
                yield return person;
        }
    }
}

然后像这样使用它:

var results = people.GetFirsts();

编辑

或通用版本GetFirsts

public static IEnumerable<TSource> GetFirsts<TSource, TKey> (this IEnumerable<TSource> source,
                                                             Func<TSource, TKey> selector,
                                                             TKey zeroValue)
{
    var set = new HashSet<TKey>();

    foreach (var item in source)
    {
        if (selector(item).Equals(zeroValue) || set.Add(selector(item)))
            yield return item;
    }
}
于 2013-07-09T14:48:27.277 回答