使用 LINQ 将多行连接成单行(CSV 属性)

Posted

技术标签:

【中文标题】使用 LINQ 将多行连接成单行(CSV 属性)【英文标题】:Use LINQ to concatenate multiple rows into single row (CSV property) 【发布时间】:2010-10-11 12:02:52 【问题描述】:

我正在寻找与 Sybase 的 LIST() 或 mysql 的 group_concat() 等效的 LINQ

它会转换:

User  Hobby
--------------
Bob   Football 
Bob   Golf 
Bob   Tennis 
Sue   Sleeping 
Sue   Drinking

收件人:

User  Hobby
--------------
Bob   Football, Golf, Tennis 
Sue   Sleeping, Drinking

【问题讨论】:

【参考方案1】:

所有答案都不够好;

因为这是一个数据库查询,但我们所有人都只是在内存中这样做;

区别是内存中的某些操作会发生错误can't trans to store expression;

var list = db.Users.GroupBy(s=>s.User).
             select(g=>newuser=g.Key,hobbys=g.select(s=>s.Hobby)); // you can just do that from db

var result=list.ToList(); // this is important,to query data to memory;

var result2 = result.select(g=>newuser=g.Key,hobbyes=string.join(",",g.hobbyes); //then,do what you love in memory

【讨论】:

【参考方案2】:

否则我们可以执行以下操作-

var users = new[]
                
                new  User="Bob", Hobby="Football" ,
                new  User="Bob", Hobby="Golf" ,
                new  User="Bob", Hobby="Tennis" ,
                new  User="Sue", Hobby="Sleeping" ,
                new  User="Sue", Hobby="Drinking" ,
                ;

                var userList = users.ToList();
                var ug = (from user in users
                          group user by user.User into groupedUserList
                          select new  user = groupedUserList.Key, hobby = groupedUserList.Select(g =>g.Hobby));

                var ug2 = (from groupeduser in ug
                          select new groupeduser.user, hobby =string.Join(",", groupeduser.hobby));

【讨论】:

【参考方案3】:

在一个 Linq 语句中完成。我没有办法推荐代码,但它表明它可以完成。

            var groupedUsers = from user in users
                           group user by user.User into userGroup
                           select new
                           
                               User = userGroup.Key,
                               userHobies =
                                   userGroup.Aggregate((a, b) => 
                                       new  User = a.User, Hobby = (a.Hobby + ", " + b.Hobby) ).Hobby
                           
                            ;
        foreach (var x in groupedUsers)
        
            Debug.WriteLine(String.Format("0 1", x.User, x.userHobies));
        

【讨论】:

【参考方案4】:

关于您问题的_concat 方面,使用:

static class EnumerableExtensions 
  
    public static String AsJoined( this IEnumerable<String> enumerable )
    
        return AsJoined( enumerable, "," );
    

    public static String AsJoined( this IEnumerable<String> enumerable, String separator )
    
        return String.Join( separator, enumerable.ToArray() );
    

bruno conde 和 Jon Skeet 的答案中的输出 foreach 可以变成:

Console.WriteLine( "User:\tHobbies");
foreach ( var group in groupedUsers )
    Console.WriteLine( "0:\t1", group.Key, group.Select( g => g.Hobby ).AsJoined( ", " ) );

...你会得到你要求的精确结果输出格式(是的,我知道其他人已经解决了你的问题,但很难抗拒!)

【讨论】:

这就像 MySQL 的 GROUP_CONCAT 函数。有用。 @Moshe LI 猜想这些天我可能会用String.Join(",", from g in group select g.Hobby) 替换group.Select( g =&gt; g.Hobby ).AsJoined( ", " )(这需要String.Join 的重载,它需要IEnumerable&lt;T&gt;,这是在.NET 4.0 中引入的) 或仅在 3.5 group.Select( g =&gt; g.Hobby ).ToArray() 上使用。【参考方案5】:

看看这个解决方案是否对你有帮助:

List<User> users = new List<User>() 
 
    new User Name = "Bob", Hobby = "Football" ,
    new User Name = "Bob", Hobby = "Golf",
    new User Name = "Bob", Hobby = "Tennis",
    new User Name = "Sue", Hobby = "Sleeping",
    new User Name = "Sue", Hobby = "Drinking"
;

var groupedUsers = from u in users
         group u by u.Name into g
         select new
         
             Name = g.First<User>().Name,
             Hobby = g.Select(u => u.Hobby)
         ;


foreach (var user in groupedUsers)

    Console.WriteLine("Name: 0", user.Name);
    foreach (var hobby in user.Hobby)
    
        Console.WriteLine("Hobby: 0", hobby);
    

【讨论】:

【参考方案6】:

这就是 GroupBy 运算符。你在使用 LINQ to Objects 吗?

这是一个例子:

using System;
using System.Collections.Generic;
using System.Linq;

public class Test

    static void Main()
    
        var users = new[]
        
            new  User="Bob", Hobby="Football" ,
            new  User="Bob", Hobby="Golf" ,
            new  User="Bob", Hobby="Tennis" ,
            new  User="Sue", Hobby="Sleeping" ,
            new  User="Sue", Hobby="Drinking" ,
        ;

        var groupedUsers = users.GroupBy(user => user.User);

        foreach (var group in groupedUsers)
        
            Console.WriteLine("0: ", group.Key);
            foreach (var entry in group)
            
                Console.WriteLine("  0", entry.Hobby);
            
        
    

这样分组 - 你能自己管理其余的吗?

【讨论】:

也可以用String.Join(", ", group.ToArray())代替内层循环,只要元素个数不是很大。 谢谢!我要自己学习 LINQ,而不是不断地打扰你 ;-) 我是唯一一个注意到男人喜欢运动而女人的爱好是睡觉和喝酒的人吗?你是可怕的乔恩·斯基特!

以上是关于使用 LINQ 将多行连接成单行(CSV 属性)的主要内容,如果未能解决你的问题,请参考以下文章

SSIS 在不使用 SQL 的情况下将多行合并并连接成单行

Apache Spark将多行连接成单行列表[重复]

在 MySQL 中将多行连接成单行

将多行连接成单行并计算 SQL Server 中连接的行数

使用 Linux 工具将多行 csv 转换为单行

将包含多个值的多行连接成 MS Access 中的单行