简体   繁体   中英

Group and count list of list items

Considering the following:

public class Board
{
    public List<Component> Components { get; set; }
}

public class Component
{
    public int Id { get; set; }
    public string Name { get; set; }
}



var data = new[]{   

    new Board{ 
        Components = new List<Component> {
            new Component{Id = 1, Name= "Item 1"},
            new Component{Id = 2, Name= "Item 2"}
        }
    }, 
    new Board{ 
        Components = new List<Component> {
            new Component{Id = 1, Name= "Item 1"},
            new Component{Id = 3, Name= "Item 3"}
        }
    },      
    new Board{ 
        Components = new List<Component> {
            new Component{Id = 2, Name= "Item 2"},
            new Component{Id = 1, Name= "Item 1"}
        }
    }, 
    new Board{ 
        Components = new List<Component> {
            new Component{Id = 1, Name= "Item 1"},
            new Component{Id = 2, Name= "Item 2"},
            new Component{Id = 3, Name= "Item 3"}
        }
    }, 
};

From this I need to get 2 lists: one containing how many times a specific component appear in all Boards and other list containing how many times those specific Component have been used together on a Board.

The first one I get using this:

var componentsCount = data.SelectMany(x => x.Components)
               .GroupBy(x => x.Id)
               .Select(x => new { Item = x.First(), Count = x.Count() });

The second one is my problem, the result should be something like this:

[
 {Count = 2, Components = [{ Id = 1, Name = "Item 1"}, { Id = 2, Name = "Item 2"}]}
 {Count = 1, Components = [{ Id = 1, Name = "Item 1"}, { Id = 3, Name = "Item 3"}]}
 {Count = 1, Components = [{ Id = 1, Name = "Item 1"}, { Id = 2, Name = "Item 2"}, { Id = 3, Name = "Item 3"}]} 
]

But I am having a hard time even starting this. Is it possible with LINQ or should I resort to foreachs and manual comparison? Any hint on how to achieve this?

You need to group your data list based on the components. You need to implement a IEqualityComparer which compares your lists based on the Id of the Components :

class ComponentListComparer : IEqualityComparer<List<Component>>
{

    public bool Equals(List<Component> x, List<Component> y)
    {
        return x.Select(c => c.Id)
            .OrderBy(c => c)
            .SequenceEqual(y.Select(c => c.Id).OrderBy(c => c));
    }

    public int GetHashCode(List<Component> obj)
    {
        return obj.Select(x => x.Id.GetHashCode() * 23).Sum();
    }

}

Then pass it to GroupBy :

 var result = data.GroupBy(x => x.Components, new ComponentListComparer())
            .Select(g => new {Count = g.Count(), Components = g.Key})
            .ToList();

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