使用LINQ将列表中的另一个列表分组

时间:2013-09-30 07:49:50

标签: c# linq group-by

考虑到以下数据结构,我希望根据列表中的列表对列表进行分组:

public class AccDocumentItem
{
   public string AccountId {get;set;}
   public List<AccDocumentItemDetail> DocumentItemDetails {get;set;}
}

public class AccDocumentItemDetail
{
   public int LevelId {get;set;}
   public int DetailAccountId {get;set;}
}

我现在有一个List<AccDocumentItem>由15个项目组成,每个项目都有一个可变数量为AccDocumentItemDetail的列表,问题是可能有AccDocumentItems个相同AccDocumentItemDetails,因此我需要将List<AccDocumentItem>分组为AccDocumentItemDetail列表。

为了更清楚,假设我的List<AccDocumentItem>列表中的前3个(15个)元素是:

1:{
   AccountId: "7102",  
   DocumentItemDetails:[{4,40001},{5,40003}]
  }
2:{
   AccountId: "7102",
   DocumentItemDetails:[{4,40001},{6,83003},{7,23423}]
  }
3:{
   AccountId: "7102",
   DocumentItemDetails:[{4,40001},{5,40003}]
  }

如何将List<AccDocumentItem>DocumentItemDetails列表分组,以便行 1 3 在他们自己的组中,并且 2 在另一组?

感谢。

1 个答案:

答案 0 :(得分:3)

您可以使用逗号分隔的detail-ID字符串进行分组:

var query = documentItemList
 .GroupBy(aci => new{ 
     aci.AccountId, 
     detailIDs = string.Join(",", aci.DocumentItemDetails
                                     .OrderBy(did => did.DetailAccountId)
                                     .Select(did => did.DetailAccountId))
 });

另一种更优雅,高效,可维护的方法是创建自定义IEqualityComparer<AccDocumentItem>

public class AccDocumentItemComparer : IEqualityComparer<AccDocumentItem>
{
    public bool Equals(AccDocumentItem x, AccDocumentItem y)
    {
        if (x == null || y == null)
            return false;
        if (object.ReferenceEquals(x, y))
            return true;
        if (x.AccountId != y.AccountId)
            return false;
        return x.DocumentItemDetails
                .Select(d => d.DetailAccountId).OrderBy(i => i)
                .SequenceEqual(y.DocumentItemDetails
                                .Select(d => d.DetailAccountId).OrderBy(i => i));
    }

    public int GetHashCode(AccDocumentItem obj)
    {
        if (obj == null) return int.MinValue;
        int hash = obj.AccountId.GetHashCode();
        if (obj.DocumentItemDetails == null)
            return hash;
        int detailHash = 0;
        unchecked
        {
            foreach (var detID in obj.DocumentItemDetails.Select(d => d.DetailAccountId))
                detailHash = detailHash * 23 + detID;
        }
        return hash + detailHash;
    }
}

现在您可以将其用于GroupBy

var query = documentItemList.GroupBy(aci => aci, new AccDocumentItemComparer());

您也可以将其用于许多其他Linq扩展方法,例如Enumerable.Join等。