简体   繁体   中英

Retain parent instance if using SelectMany on nested collection

I have a collection of my model Person :

class Person
{
    public string FirstName {get; set;}
    public string LastName {get; set;}
    public string Company {get; set;}
    public IEnumerable<string> Tags {get; set;}
}

and would transform this one by LINQ into another collection grouped by tags. How can I do that?

My approach so far:

var result = PersonCollection
    .SelectMany(m => m.Tags)
    .GroupBy(b => b);

But this throws all informations about the person away.

You can persist the Person in an anonymous type:

var result = PersonCollection
    .SelectMany(p => p.Tags.Select(t => new{ Person = p, Tag = t }))
    .GroupBy(x => x.Tag);

Now these groups still contain the tags as key and the persons:

foreach (var tagPersons in result)
{
    Console.WriteLine($"Tag: {tagPersons.Key}");
    Console.Write($" all persons: {string.Join(",", tagPersons.Select(x => x.Person.LastName))}");
}

You need to group people by each tag. This looks best in LINQ query syntax :

var groupings =
    from p in people
    from tag in p.Tags
    group p by tag into g
    select new
    {
        Tag = g.Key,
        People = g.ToList()
    };

Last select is just for friendly names, this would have worked as well:

var gg = from p in people
         from tag in p.Tags
         group p by tag;

Behind the scenes this is equivalent to @Tim Schmelter's solution

When you use GroupBy() You are essentially making another collection of objects using only those properties. You need to either include all of the information that you want in the grouping. Or you can use a meaningful "key" in your grouping and use another query to find the rest of the information from your original collection. Something like.

    var fullObject = collection.ElementAt(GroupingIndex);

or

    var fullObject = collection.Where(search => search.prop1 = "foo" && search.prop2 = "bar");

The constraints here are that you need an index or some hard coded value to search the collection.

Because you have grouped by b => b , a better solution would be to move this anonymous object into a POCO . Then you have an object you can address directly in a separate search.

    .GroupBy(b => b)
    .Select(grouped => new GroupedObj { B = grouped.Key.b});

Then you can use that collection of grouped results in some form or loop or index etc and get what you want from there. Then use that to get what you want from the original collection (where the more information is).

Badly written answer i know.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM