按多列分组

发布于 2024-07-19 15:56:35 字数 436 浏览 8 评论 0原文

我如何在 LINQ 中对多列进行 GroupBy

与 SQL 中类似的操作:

SELECT * FROM <TableName> GROUP BY <Column1>,<Column2>

如何将其转换为 LINQ:

QuantityBreakdown
(
    MaterialID int,
    ProductID int,
    Quantity float
)

INSERT INTO @QuantityBreakdown (MaterialID, ProductID, Quantity)
SELECT MaterialID, ProductID, SUM(Quantity)
FROM @Transactions
GROUP BY MaterialID, ProductID

How can I do GroupBy multiple columns in LINQ

Something similar to this in SQL:

SELECT * FROM <TableName> GROUP BY <Column1>,<Column2>

How can I convert this to LINQ:

QuantityBreakdown
(
    MaterialID int,
    ProductID int,
    Quantity float
)

INSERT INTO @QuantityBreakdown (MaterialID, ProductID, Quantity)
SELECT MaterialID, ProductID, SUM(Quantity)
FROM @Transactions
GROUP BY MaterialID, ProductID

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

予囚 2024-07-26 15:56:35

使用匿名类型。

例如

group x by new { x.Column1, x.Column2 }

Use an anonymous type.

Eg

group x by new { x.Column1, x.Column2 }
末骤雨初歇 2024-07-26 15:56:35

程序示例:

.GroupBy(x => new { x.Column1, x.Column2 })

Procedural sample:

.GroupBy(x => new { x.Column1, x.Column2 })
南城追梦 2024-07-26 15:56:35

好的,得到这个:

var query = (from t in Transactions
             group t by new {t.MaterialID, t.ProductID}
             into grp
                    select new
                    {
                        grp.Key.MaterialID,
                        grp.Key.ProductID,
                        Quantity = grp.Sum(t => t.Quantity)
                    }).ToList();

Ok got this as:

var query = (from t in Transactions
             group t by new {t.MaterialID, t.ProductID}
             into grp
                    select new
                    {
                        grp.Key.MaterialID,
                        grp.Key.ProductID,
                        Quantity = grp.Sum(t => t.Quantity)
                    }).ToList();
过度放纵 2024-07-26 15:56:35

对于按多列分组,请尝试此操作...

GroupBy(x=> new { x.Column1, x.Column2 }, (key, group) => new 
{ 
  Key1 = key.Column1,
  Key2 = key.Column2,
  Result = group.ToList() 
});

您可以使用相同的方式添加 Column3、Column4 等。

For Group By Multiple Columns, Try this instead...

GroupBy(x=> new { x.Column1, x.Column2 }, (key, group) => new 
{ 
  Key1 = key.Column1,
  Key2 = key.Column2,
  Result = group.ToList() 
});

Same way you can add Column3, Column4 etc.

少女净妖师 2024-07-26 15:56:35

从 C# 7 开始,您还可以使用值元组:

group x by (x.Column1, x.Column2)

.GroupBy(x => (x.Column1, x.Column2))

Since C# 7 you can also use value tuples:

group x by (x.Column1, x.Column2)

or

.GroupBy(x => (x.Column1, x.Column2))
鱼窥荷 2024-07-26 15:56:35

使用元组推断元组元素名称C# 7.1或更高版本(目前它仅适用于linq to objects并且它当需要表达式树时不支持,例如someIQueryable.GroupBy(...)。 ">Github 问题):

// declarative query syntax
var result = 
    from x in inMemoryTable
    group x by (x.Column1, x.Column2) into g
    select (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity));

// or method syntax
var result2 = inMemoryTable.GroupBy(x => (x.Column1, x.Column2))
    .Select(g => (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity)));

C# 3 或更高版本使用匿名类型

// declarative query syntax
var result3 = 
    from x in table
    group x by new { x.Column1, x.Column2 } into g
    select new { g.Key.Column1, g.Key.Column2, QuantitySum = g.Sum(x => x.Quantity) };

// or method syntax
var result4 = table.GroupBy(x => new { x.Column1, x.Column2 })
    .Select(g => 
      new { g.Key.Column1, g.Key.Column2 , QuantitySum= g.Sum(x => x.Quantity) });

C# 7.1 or greater using Tuples and Inferred tuple element names (currently it works only with linq to objects and it is not supported when expression trees are required e.g. someIQueryable.GroupBy(...). Github issue):

// declarative query syntax
var result = 
    from x in inMemoryTable
    group x by (x.Column1, x.Column2) into g
    select (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity));

// or method syntax
var result2 = inMemoryTable.GroupBy(x => (x.Column1, x.Column2))
    .Select(g => (g.Key.Column1, g.Key.Column2, QuantitySum: g.Sum(x => x.Quantity)));

C# 3 or greater using anonymous types:

// declarative query syntax
var result3 = 
    from x in table
    group x by new { x.Column1, x.Column2 } into g
    select new { g.Key.Column1, g.Key.Column2, QuantitySum = g.Sum(x => x.Quantity) };

// or method syntax
var result4 = table.GroupBy(x => new { x.Column1, x.Column2 })
    .Select(g => 
      new { g.Key.Column1, g.Key.Column2 , QuantitySum= g.Sum(x => x.Quantity) });
你没皮卡萌 2024-07-26 15:56:35

您还可以使用 Tuple<> 对于强类型分组。

from grouping in list.GroupBy(x => new Tuple<string,string,string>(x.Person.LastName,x.Person.FirstName,x.Person.MiddleName))
select new SummaryItem
{
    LastName = grouping.Key.Item1,
    FirstName = grouping.Key.Item2,
    MiddleName = grouping.Key.Item3,
    DayCount = grouping.Count(), 
    AmountBilled = grouping.Sum(x => x.Rate),
}

You can also use a Tuple<> for a strongly-typed grouping.

from grouping in list.GroupBy(x => new Tuple<string,string,string>(x.Person.LastName,x.Person.FirstName,x.Person.MiddleName))
select new SummaryItem
{
    LastName = grouping.Key.Item1,
    FirstName = grouping.Key.Item2,
    MiddleName = grouping.Key.Item3,
    DayCount = grouping.Count(), 
    AmountBilled = grouping.Sum(x => x.Rate),
}
遥远的绿洲 2024-07-26 15:56:35

虽然这个问题询问的是按类属性分组,但如果您想针对 ADO 对象(如 DataTable)按多个列进行分组,则必须将“新”项分配给变量:

EnumerableRowCollection<DataRow> ClientProfiles = CurrentProfiles.AsEnumerable()
                        .Where(x => CheckProfileTypes.Contains(x.Field<object>(ProfileTypeField).ToString()));
// do other stuff, then check for dups...
                    var Dups = ClientProfiles.AsParallel()
                        .GroupBy(x => new { InterfaceID = x.Field<object>(InterfaceField).ToString(), ProfileType = x.Field<object>(ProfileTypeField).ToString() })
                        .Where(z => z.Count() > 1)
                        .Select(z => z);

Though this question is asking about group by class properties, if you want to group by multiple columns against a ADO object (like a DataTable), you have to assign your "new" items to variables:

EnumerableRowCollection<DataRow> ClientProfiles = CurrentProfiles.AsEnumerable()
                        .Where(x => CheckProfileTypes.Contains(x.Field<object>(ProfileTypeField).ToString()));
// do other stuff, then check for dups...
                    var Dups = ClientProfiles.AsParallel()
                        .GroupBy(x => new { InterfaceID = x.Field<object>(InterfaceField).ToString(), ProfileType = x.Field<object>(ProfileTypeField).ToString() })
                        .Where(z => z.Count() > 1)
                        .Select(z => z);
多像笑话 2024-07-26 15:56:35

需要注意的是,您需要为 Lambda 表达式发送一个对象,并且不能使用类的实例。

示例:

public class Key
{
    public string Prop1 { get; set; }

    public string Prop2 { get; set; }
}

这将编译,但将生成每个周期一个密钥

var groupedCycles = cycles.GroupBy(x => new Key
{ 
  Prop1 = x.Column1, 
  Prop2 = x.Column2 
})

如果您不想命名关键属性然后检索它们,您可以这样做。 这将正确地 GroupBy 并为您提供关键属性。

var groupedCycles = cycles.GroupBy(x => new 
{ 
  Prop1 = x.Column1, 
  Prop2= x.Column2 
})

foreach (var groupedCycle in groupedCycles)
{
    var key = new Key();
    key.Prop1 = groupedCycle.Key.Prop1;
    key.Prop2 = groupedCycle.Key.Prop2;
}

A thing to note is that you need to send in an object for Lambda expressions and can't use an instance for a class.

Example:

public class Key
{
    public string Prop1 { get; set; }

    public string Prop2 { get; set; }
}

This will compile but will generate one key per cycle.

var groupedCycles = cycles.GroupBy(x => new Key
{ 
  Prop1 = x.Column1, 
  Prop2 = x.Column2 
})

If you wan't to name the key properties and then retreive them you can do it like this instead. This will GroupBy correctly and give you the key properties.

var groupedCycles = cycles.GroupBy(x => new 
{ 
  Prop1 = x.Column1, 
  Prop2= x.Column2 
})

foreach (var groupedCycle in groupedCycles)
{
    var key = new Key();
    key.Prop1 = groupedCycle.Key.Prop1;
    key.Prop2 = groupedCycle.Key.Prop2;
}
耳根太软 2024-07-26 15:56:35
var Results= query.GroupBy(f => new { /* add members here */  });
var Results= query.GroupBy(f => new { /* add members here */  });
画中仙 2024-07-26 15:56:35

通过 new { x.Col, x.Col} 对 x 进行分组

group x by new { x.Col, x.Col}

寂寞清仓 2024-07-26 15:56:35

.GroupBy(x => (x.MaterialID, x.ProductID))

.GroupBy(x => (x.MaterialID, x.ProductID))

人事已非 2024-07-26 15:56:35
.GroupBy(x => x.Column1 + " " + x.Column2)
.GroupBy(x => x.Column1 + " " + x.Column2)
つ可否回来 2024-07-26 15:56:35

对于VB匿名/lambda

query.GroupBy(Function(x) New With {Key x.Field1, Key x.Field2, Key x.FieldN })

For VB and anonymous/lambda:

query.GroupBy(Function(x) New With {Key x.Field1, Key x.Field2, Key x.FieldN })
倾城泪 2024-07-26 15:56:35

其他答案适用于固定\静态列,您知道在编码时要对哪些内容进行分组。 但是,如果您在程序运行之前不知道要按哪些列或多少列进行分组,您可以执行以下操作:

public class GroupingKey<T> : IEquatable<GroupingKey<T>>
{
    public T[] Groups { get; init; }
    static EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;

    public GroupingKey(T[] groups)
    {
        Groups = groups;
    }

    public override int GetHashCode()
    {
        var hc = new HashCode();
        foreach (var g in Groups)
            hc.Add(g);
        return hc.ToHashCode();
    }

    public override bool Equals(object? other)
    {
        return Equals(other as GroupingKey<T>);
    }

    public bool Equals(GroupingKey<T>? other)
    {
        if (other == null)
            return false;

        if (ReferenceEquals(this, other))
            return true;

        if (Groups.Length != other.Groups.Length)
            return false;

        for (int i = 0; i < Groups.Length; i++)
        {
            if (!equalityComparer.Equals(Groups[i], other.Groups[i]))
                return false;
        }

        return true;
    }

    public override string ToString()
    {
        string[] array = new string[Groups.Length];
        for (int i = 0; i < Groups.Length; i++)
            array[i] = $"Group{i} = {Groups[i]}";

        return $"{{ {string.Join(", ", array)} }}";
    }
}

示例使用:

public void GroupByAnyColumns(List<string[]> rows, List<int> groupByColumnIndexes)
{
    var grouped = rows.GroupBy(row => new GroupingKey<string>(groupByColumnIndexes.Select(colIdx => row[colIdx]).ToArray()));
}

Other answers are good for fixed\static columns, where you know what to group on when you code. But if you do not know which or how many columns to group by until the program is run, you could do something like:

public class GroupingKey<T> : IEquatable<GroupingKey<T>>
{
    public T[] Groups { get; init; }
    static EqualityComparer<T> equalityComparer = EqualityComparer<T>.Default;

    public GroupingKey(T[] groups)
    {
        Groups = groups;
    }

    public override int GetHashCode()
    {
        var hc = new HashCode();
        foreach (var g in Groups)
            hc.Add(g);
        return hc.ToHashCode();
    }

    public override bool Equals(object? other)
    {
        return Equals(other as GroupingKey<T>);
    }

    public bool Equals(GroupingKey<T>? other)
    {
        if (other == null)
            return false;

        if (ReferenceEquals(this, other))
            return true;

        if (Groups.Length != other.Groups.Length)
            return false;

        for (int i = 0; i < Groups.Length; i++)
        {
            if (!equalityComparer.Equals(Groups[i], other.Groups[i]))
                return false;
        }

        return true;
    }

    public override string ToString()
    {
        string[] array = new string[Groups.Length];
        for (int i = 0; i < Groups.Length; i++)
            array[i] = 
quot;Group{i} = {Groups[i]}";

        return 
quot;{{ {string.Join(", ", array)} }}";
    }
}

Example use:

public void GroupByAnyColumns(List<string[]> rows, List<int> groupByColumnIndexes)
{
    var grouped = rows.GroupBy(row => new GroupingKey<string>(groupByColumnIndexes.Select(colIdx => row[colIdx]).ToArray()));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文