【问题标题】:How to update an element value with the duplicated value?如何使用重复值更新元素值?
【发布时间】:2019-07-15 20:41:52
【问题描述】:

如何用重复值更新元素值?

假设我的列表中有 4 个元素,如您所见,有 Dog1 和 Dog2 元素:

名称:Dog1 价格:NULL 年龄:14 ImportDate = 14.07.2019 15:00

名称:Dog1 价格:NULL 年龄:17 ImportDate = 14.07.2019 14:00

名称:Dog1 价格:14.00 年龄 = 13 ImportDate = 14.07.2019 13:00

名称:Dog2 价格:NULL 年龄:14 ImportDate = 14.07.2019 16:00

名称:Dog2 价格:NULL 年龄:17 ImportDate = 14.07.2019 10:00

名称:Dog2 价格:22.00 年龄 = 13 ImportDate = 14.07.2019 09:00

在列表中的这些元素中,我只想保留最新 ImportDate 的狗,同时我想保留列表中的这两个元素:

名称:Dog1 价格:NULL 年龄:14 ImportDate = 14.07.2019 15:00

名称:Dog2 价格:NULL 年龄:14 ImportDate = 14.07.2019 16:00

在下面,我提供了一条代码线,将这两条狗保留在列表中,并删除其余的。

    dogList
      .GroupBy(x => new { 
         x.Name, 
         x.ImportDate.Date 
       })
      .Select(g => g
         .OrderByDescending(x => x.ImportDate)
         .First())
      .ToList();

但是我保留在列表中的两条狗没有任何价格。 我想做的是为这些价值为 NULL 的狗设置价格,以便在特定日期对现有狗有价格,在这种情况下,最新的 dog1 应该有 14:00 的价格,而 dog2 应该有价格 22.

我怎样才能做到这一点? 我想我需要从列表中找到元素,然后找到狗的名字和 importdate 的价格。然后用结算更新列表中的元素

更新列表中的值后,结果应如下所示:

名称:Dog1 价格:14.00 年龄:14 ImportDate = 14.07.2019 15:00

名称:Dog1 价格:14.00 年龄:17 ImportDate = 14.07.2019 14:00

名称:Dog1 价格:14.00 年龄 = 13 ImportDate = 14.07.2019 13:00

名称:Dog2 价格:22.00 年龄:14 ImportDate = 14.07.2019 16:00

名称:Dog2 价格:22.00 年龄:17 ImportDate = 14.07.2019 10:00

名称:Dog2 价格:22.00 年龄 = 13 ImportDate = 14.07.2019 09:00

最终结果应该是包含这些元素的列表:

名称:Dog1 价格:14.00 年龄:14 ImportDate = 14.07.2019 15:00

名称:Dog2 价格:22.00 年龄:14 ImportDate = 14.07.2019 16:00

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    我建议创建 Dog 每个组的实例:

    var filtered = dogList
      .GroupBy((item => new { 
         item.Name, 
         item.ImportDate.Date 
       })
      .Select(chunk => new Dog() { //TODO: Use the right syntax here
         Name       = chunk.Key.Name,
         ImportDate = chunk.Max(item => item.ImportDate), 
         Age        = chunk
           .Aggregate((s, a) => s.ImportDate < a.ImportDate ? s : a)
           .Age,  
         Price      = chunk.Where(item => item.Price.HasValue).Max(item => item.Price.Value)
       })
      .ToList();
    

    编辑: 主要原则(创建新的Dog 实例)保持不变,我们可能想更改上一个Select 中的一些评估:

    Name - 块的名称:

       Name = chunk.Key.Name
    

    ImportDate - 最大可能:

       ImportDate = chunk.Max(item => item.ImportDate), 
    

    Age - 与ImportDate 对应的年龄。在这里我们必须计算ArgMax(或MaxBy),它在标准Linq未预置(在MoreLinq中实现);但可以用Aggregate模拟

         Age = chunk
           .Aggregate((s, a) => s.ImportDate < a.ImportDate ? s : a)
           .Age
    

    最后,Price 不为空最高价:

         Price = chunk.Where(item => item.Price.HasValue).Max(item => item.Price.Value)
    

    【讨论】:

    • 感谢您的回复。 @Dmitry Bychenko 这会更新这些元素并根据 Importdate.Date 选择最新的元素以保留在这些重复项的列表中吗?
    • 我更新了话题,我发现我有点太快了。
    • 假设 dog() 类型是否有另一个名为 HairColor 的属性。假设我也想保留它的原始颜色,不需要更新。它适用于您的代码吗?
    • @Ken Kaneki:如果Dog 实例可以有一些您想要保留的其他属性(例如,Color),您应该将它们添加到Select(其中Color 应该是取自几只狗?)或切换到 Tim Schmelter 的解决方案:提取 Dog 实例并修改它。
    【解决方案2】:

    如果您不想或不能创建新实例,您可以使用这种方法:

    dogList = dogList
        .GroupBy(d => d.Name)
        .Select(dogGroup =>
        {
            Dog latestDog = dogGroup.OrderByDescending(d => d.ImportDate).First();
            if (!latestDog.Price.HasValue)
            {
                latestDog.Price = dogGroup
                    .FirstOrDefault(dog => dog.Price.HasValue)?.Price.Value ?? null;
            }
            return latestDog;
        })
        .ToList();
    

    【讨论】:

    • .FirstOrDefault(dog => dog.Price.HasValue)?.Price.Value ??无效的;如果 name 和 importdate 分组的所有元素都没有 price 怎么办?我怎样才能将其设置为空? :) 我有时会收到“序列不包含匹配元素”。非常感谢:D
    • 假设我要使用这段代码,我应该为此创建一个新方法吗?我传入一个数据列表并返回一个新列表? :)
    • 假设我有一个方法可以创建和修改所有这些狗元素。在返回之前,我想执行你的代码来解决我所描述的问题,将它放在我的方法中或创建一个新的然后调用它是否有意义?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    • 1970-01-01
    • 1970-01-01
    • 2022-09-23
    • 1970-01-01
    • 2019-01-23
    相关资源
    最近更新 更多