如何使用linq c#对列表进行分组

kpbwa7wx  于 2022-12-06  发布在  C#
关注(0)|答案(3)|浏览(220)

我的方案如下:
我有以下数据-

ID,名称,类型,位置,组ID

1, samename, Rock, New York, 12
2, samename, Jazz, Sydney, 12
3, samename, Rock, Sydney, 12
4, samename, Jazz, New York, 12    
5, name3, Opera House, Sydney, 14
6, name3, Opera House, London, 14
7, name2, Emirates, London, 13

我希望输出基于GroupID的平面化数据,如下所示

ID,名称,地点,位置,组ID

1, samename, {Rock,Jazz}, {New York,Sydney}, 12
5, name3, Opera House, {Sydney,London}, 14
7, name2, Emirates, London, 13

这是我继承的非常糟糕的设计-我正在努力使它更好..而不打破旧代码。
我相信答案与SelectMany有关--但我无法找出语法--我尝试了几种不同的方法。
我尝试的解决方案-没有展平..

var q3 = Data.Where(b=>b.GroupID != null).GroupBy(x=> new { x.GroupID }, (key, group) => new 
{ 
  GroupID = key.GroupID,  
  Result =  group.Select(g=> new 
                         {                            
                           Type = g.Type, 
                           Location = g.Location,                                                  
                         }).ToList()
});
koaltpgm

koaltpgm1#

试试这个:

var answer = data.GroupBy(x => x.GroupID).Select(x => new { 
     ID = x.Min(y => y.ID),
     Name = x.Select(y => y.Name).ToList(),
     Type = x.Select(y => y.Type).ToList(),
     Location = x.Select(y => y.Location).ToList(),
     GroupID = x.Key
}).ToList();
k3fezbri

k3fezbri2#

试试这个:

var q = Data.Where(b => b.GroupID != null).GroupBy((x) => x.GroupID).Select((y) => new
                {
                    GroupID = y.First().ID,
                    Name = string.Join(",", y.Select((k) => k.Name).Distinct()),
                    Type = string.Join(",", y.Select(( k) => k.Type).Distinct()),
                    Location = string.Join(",", y.Select(( k) => k.Location).Distinct()),
                });

如果要动态加载列,请使用以下代码:

var q2 = Data.Where(b => b.GroupID != null).GroupBy((x) => x.GroupID).Select((y) => new
        {
            GroupID = y.First().ID,
            result = DynamicGroup(y)
        });

    private static string DynamicGroup(IGrouping<string,DataD> y)
    {
        string result=null;
        foreach (System.Reflection.PropertyInfo pInfo in typeof(DataD).GetProperties().Where(x=>x.Name!="GroupID" && x.Name!="ID"))
        {
            result += string.Format(" {0} ; ",string.Join(",", y.Select((k) => pInfo.GetValue(k, null)).Distinct()));
        }
        return result;
    }
polkgigr

polkgigr3#

如果您有一个元素序列,其中包含一个内部元素序列,并且您希望将所有内部元素序列作为一个序列来访问,则可以使用SelectMany
SelectMany类似于以下代码:

List<InnerClass> result = new List<InnerClass>()

foreach (var outerElement in outerSequence)
{
    foreach (InnerClass innerElement in outerSequence.InnerSequence)
    {
        // note that InnerSequence is an IEnumerable in every InnerElement
        result.Add(innerElement);
    }
}

你想要的正好相反:你想把集合中的几个元素组合成一个新的序列。2你的源代码中使用的所有名称应该产生一个具有几个字段的元素:

  • 名称是所有同名元素的名称
  • Id是此名称的所有元素的最小Id
  • Place是一个序列中所有Type在你的序列中都有这个Name(摇滚,爵士,酋长)(有点不吉利的名字)
  • 位置是具有名称的所有位置的序列
  • GroupId是名称为的项目的GroupId

在您的示例中,Name对应于GroupId。您确定不能有两个元素具有“samename”和不同的GroupId吗?
第一步是使用GroupBy对所有具有相同名称的元素进行分组:
如果您想创建一个新的集合,请使用下面的方法:
现在你有了一个IGrouping项的集合,每个IGrouping项是一个具有相同名称的源元素序列,每个IGrouping项都有一个包含这个共同名称的Key属性。
第二步是将每个组中的所有元素转换为Id序列、Place序列和GroupId序列:

var result2 = result1.Select(group => new
{
    Name = group.Key,
    AllIds = group.Select(groupElement => groupElement.Id),
    Places = group.Select(groupElement => groupElement.Place),
    Locations = group.Select(groupElement => groupElement.Location),
    GroupIds = group.Selelect(groupElement => groupElement.GroupId),
};

从result1中的每个组中,创建一个具有属性Name的新对象,其中包含组的Key(它是所有groupElements中的公用名称)。此创建的对象还具有属性Places,它来自组中的每个元素Place。每个创建的对象还具有属性Locations,它是......等等。
现在你要做的就是从AllIds中得到最小的值,从Groupids中得到唯一的值:

var result3 = result2.Select(item => new
{
    Name = item.Name,
    LowestId = item.AllIds.Orderby(id => id).First(),
    Places = item.Places,
    Locations = item.Locations,
    OneAndOnlyGroupId = item.GroupId.First(),
};

如果您不确定具有相同Name的所有元素是否都具有相同的GroupId,请考虑按new {Name = sourceElement.Name, GrouId = sourceElement.GroupId)分组,以创建具有相同{Name, GroupId}的组,或者如果GroupIds

相关问题