使用LINQ对深层嵌套对象进行分组

时间:2017-07-11 16:51:56

标签: c# list linq group-by

我有以下课程:

public class Item
{
    public int Id { get; set; }
    public string Sku { get; set; }
    public List<Price> Prices { get; set; }
}

public class Price
{
    public int Id { get; set; }
    public double Cost { get; set; }
    public PriceList List { get; set; }
}

public class PriceList
{
    public int Id { get; set; }
    public string FileName { get; set; }
    public DateTime ImportDateTime { get; set; }
}

基本上,它是一个项目列表[Item],其中每个项目都有一个价格列表[List<Price> Prices](一对多),每个价格都有一个价目表[PriceList List](一对一)。

我需要的是所有价目表的清单。

看起来我需要的是一个小组到一个&#34;孙子&#34;,基本上,按PriceList&#39; Id分组({{1} },而在列表中的Price下面。)

因此,作为一个例子,如果我有五个价目表,它应该返回五行。

我做到了以下很长的路要走:

Item

如何使用LINQ实现?

更新

这是一个基本的样本集:

List<PriceList> priceLists = new List<PriceList>();

foreach (Item item in items)
{
    foreach (Price price in item.Prices)
    {
        PriceList list = price.List;

        if (!priceLists.Any(x => x.Id == list.Id))
        {
            priceLists.Add(list);
        }
    }
}

让我们从头到尾开始:

  1. 我有PriceList priceList1 = new PriceList { Id = 1, FileName = "Price List 1.csv" }; PriceList priceList2 = new PriceList { Id = 2, FileName = "Price List 2.csv" }; Price price1 = new Price { Id = 1, Cost = 2.65, List = priceList1 }; Price price2 = new Price { Id = 2, Cost = 14.23, List = priceList2 }; Price price3 = new Price { Id = 3, Cost = 29.01, List = priceList1 }; Price price4 = new Price { Id = 4, Cost = 1, List = priceList2 }; Price price5 = new Price { Id = 5, Cost = 56.12, List = priceList1 }; Item item1 = new Item { Id = 1, Sku = "item1", Prices = new List<Price> { price1, price2 } }; Item item2 = new Item { Id = 2, Sku = "item2", Prices = new List<Price> { price3, price4 } }; Item item3 = new Item { Id = 3, Sku = "item3", Prices = new List<Price> { price5 } }; List<Item> itemsList = new List<Item> { item1, item2, item3 }; Item)的列表,其中包含三个itemsList
  2. 每个Item都有一个Item列表。
  3. 每个Price都有一个Price
  4. 澄清所有这些背后的原因:用户导入他们定期从供应商处获得的价格(价格表)电子表格,价格波动,每个价格表对同一商品的价格不同。因此,具有多个价格和每个价格的物品的原因有其用于上传它的价目表(PriceList类中包含的更多信息,我省略了它以保持简单)。 / p>

    我希望我能清楚。

2 个答案:

答案 0 :(得分:1)

这似乎是你想要的,使用扩展来通过lambda表达式做区别:

var ans = itemsList.SelectMany(item => item.Prices.Select(price => price.List)).DistinctBy(price => price.Id);

扩展名如下:

public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> src, Func<T, TKey> keyFun) {
    var seenKeys = new HashSet<TKey>();
    foreach (T e in src)
        if (seenKeys.Add(keyFun(e)))
            yield return e;
}

如果您改变了使用HashSet<Int>来跟踪所见ID的方法,那么您可能会比LINQ更有效率。

答案 1 :(得分:0)

看起来您可以将SelectMany(以获取所有Prices列表)与Select合并(以获取所有相关的PriceList属性):

List<PriceList> priceLists = items.SelectMany(i => i.Prices).Select(p => p.List).ToList();

修改

以上内容将返回所有PriceLists,但由于许多Items可能引用相同的PriceList,因此您需要一种方法来过滤PriceList.Id字段。

执行此操作的一种方法是覆盖Equals对象的GetHashCodePriceList属性。如果您确实认为两个PriceList对象具有相同的Id,那么您可以执行以下操作:

public class PriceList
{
    public int Id { get; set; }
    public string FileName { get; set; }
    public DateTime ImportDateTime { get; set; }

    public override bool Equals(object obj)
    {
        var other = obj as PriceList;
        return Id == other?.Id;
    }

    public override int GetHashCode()
    {
        return Id;
    }
}

这允许您在价格上使用Linq方法Distinct(它会调用Equals方法来区分结果中的PriceLists

List<PriceList> priceLists = items
    .SelectMany(i => i.Prices)
    .Select(i => i.List)
    .Distinct()
    .ToList();