C#GroupBy动态值-未知参数-C#Lambda GroupBy EqualityComparer

时间:2019-06-12 21:40:17

标签: c# lambda group-by

我想对某些列进行分组分组,但是它们可能会有所不同,并且我不想对将要分组的字段进行硬编码。

我尝试过:

users.GroupBy(groupingColumnIndexes.Select(a => x.ColumnValues[a])) 

...

List<Row> users = new List<Row>()
        {
            new Row("John", "Doe", "10"),
            new Row("John", "Doe", "45"),
            new Row("Will","Smith", "26"),
            new Row("Will", "Smith", "52"),
            new Row("Julius", "Cesar", "23")
        };

        List<int> groupingColumnIndexes = new List<int>() { 0, 1 };

        List<User> output = users
            .GroupBy(x => {
                    // INFO: if I'd return groupingColumns code would not group users correctly.
                    var groupingColumns = groupingColumnIndexes.Select(a => x.ColumnValues[a]);

                    string col1Value = x.ColumnValues[0];
                    string col2Value = x.ColumnValues[1];

                    // Result below is working, but I would rather build more dynamic version.
                    var result =  new { col1Value, col2Value };
                    return result;
                })
            .Select(x => new User
            {
                Name = string.Join(",", x.Key),
                Age = (int)x.Sum(a => int.Parse(a.ColumnValues[2])),
                LastName = string.Empty
            }).ToList();

.NET小提琴:https://dotnetfiddle.net/cPuafD

预期: 约翰·多伊55 威尔·史密斯78 朱利叶斯·塞萨尔23

使用GroupBy(list)时的实际值: 约翰,母鹿10 约翰,母鹿45 威尔·史密斯26 威尔·史密斯52 撒撒利亚朱利叶斯23

2 个答案:

答案 0 :(得分:1)

得到了改进,@ Xiaoy312的回答使它看起来更容易理解。

public class StringColumnEqualityComparer : IEqualityComparer<List<string>>
{
    public StringColumnEqualityComparer()
    {

    }

    public bool Equals(List<string> x, List<string> y) {
        bool output = x.SequenceEqual(y);
        return output;
    }

    public int GetHashCode(List<string> obj)
    {
        int output = obj.Aggregate(13, (hash, y) => hash * 7 + y?.GetHashCode() ?? 0);
        return output;
    }
}

用法:

List<Row> users = new List<Row>()
{
    new Row("John", "Doe", "10"),
    new Row("John", "Doe", "45"),
    new Row("Will","Smith", "26"),
    new Row("Will", "Smith", "52"),
    new Row("Julius", "Cesar", "23")
};

List<int> groupingColumnIndexes = new List<int>() { 0, 1 };

List<User> output = users
            .GroupBy(x =>
                 groupingColumnIndexes.Select(c => x.ColumnValues[c]).ToList(),
                 new StringColumnEqualityComparer()
            )
            .Select(x => new User
            {
                Name = string.Join(',', x.Key),
                Age = (int)x.Sum(a => int.Parse(a.ColumnValues[2])),
                LastName = string.Empty
            }).ToList();

答案 1 :(得分:0)

您需要为列IEqualityComparer实现GroupBy

class LambdaComparer<T> : IEqualityComparer<T>
{
    private readonly Func<T, T, bool> equals;
    private readonly Func<T, int> getHashCode;

    public LambdaComparer(Func<T, T, bool> equals, Func<T, int> getHashCode)
    {
        this.equals = equals;
        this.getHashCode = getHashCode;
    }

    public bool Equals(T x, T y) => equals(x, y);
    public int GetHashCode(T obj) => getHashCode(obj);
}

var output = users
    .GroupBy(
        x => groupingColumnIndexes.Select(i => x.ColumnValues[i]).ToArray(),
        new LambdaComparer<string[]>((a, b) => a.SequenceEqual(b), x => x.Aggregate(13, (hash, y) => hash * 7 + y?.GetHashCode() ?? 0))
    )
    .Select(g => new User
    {
        Name = g.Key[0],
        LastName = g.Key[1],
        Age = g.Sum(x => int.Parse(x.ColumnValues[2]))
    })
    .ToList();