【问题标题】:How can I use LINQ to get a property matching a conditional sum?如何使用 LINQ 获取与条件总和匹配的属性?
【发布时间】:2018-01-04 17:51:22
【问题描述】:

好的,我的标题听起来很奇怪,但这是我的场景。我认为这是一个简单的查询,但很难在纸上解释。我自己也遇到了 LINQ 的问题。最好举例说明:

我有一个对象列表(在伪代码中),如下所示:

var data = [
  {
    quantity: 123,
    rate: 0.12
  },
  {
    quantity: 456,
    rate: 0.13
  },
  {
    quantity: 3,
    rate: 0.14
  },
  {
    quantity: 92,
    rate: 0.15
  }
]

我正在尝试生成一个返回 rateLINQ 查询,该查询等于输入数量的总和。

举例说明:

使用上面的示例数据,我想找到与581(来自其他地方的变量输入)的总量相匹配的rate。我列表中的前三个对象的数量总计为 582,因此我希望我的 LINQ 查询返回 0.14rate 匹配条件,即总 quantity 字段大于我的输入数量)。

我应该可以使用 LINQ 来执行此操作,对吗?它有点像.Sum.Where,这就是我感到困惑的地方。

是否有任何参考资料可以解决这种情况? 有人有写“条件总和”的经验吗?

【问题讨论】:

  • 我个人认为 Linq 这样做比简单的循环更难阅读。
  • 或者,如果您执行foreach(var item in data),您可以添加 item.quantity 并在数量达到/超过阈值时返回 item.rate
  • 一条长的单线通常会让生活变得艰难;(
  • 你的问题不一致;你说你希望总数等于一个目标值和超过一个目标值。是哪个?
  • 任何数量都可以是负数吗?

标签: c# linq


【解决方案1】:

在函数式编程中,这将是 reduce 的变体。在 LINQ 中,Aggregate 方法可用于此目的。伪 LINQ:

var limit = 581;
var rate = data.Aggregate((acc, cur) =>
{
    if (acc.quantity < limit)
    {
        return new
        {
            quantity = acc.quantity + cur.quantity,
            rate = cur.rate
        };
    }
    else
    {
        return acc;
    }
}).rate;

编辑:更紧凑的单行版本:

var rate = data.Aggregate((acc,cur) => acc.quantity < limit ? new { quantity = acc.quantity + cur.quantity, rate = cur.rate } : acc).rate;

【讨论】:

  • 这正是我想要的。之前没有使用过Aggregate,它看起来可以回答我的问题。谢谢!
【解决方案2】:

本来想找Aggregate,但没有进入一行:(

对于 one-liner 的期望,这是 LINQ 的一个有趣用法:)

var target = 581;
var sum = 0;
var rate = data.First(i =>(sum += i.Quantity) > target).Rate; // 0.14

【讨论】:

  • 这对我来说有点吓人,因为总和被 LINQ 表达式中的闭包改变了。例如,如果数据是 ParallelEnumerable,这可能会导致问题。我在答案中添加了一个使用聚合的单行版本。
  • @AaronM.Eshbach 在技术上是正确的。地球上没有人会喜欢那条线...当您发布答案时,我正在努力使用Aggregate而不使用new;P
  • 永远不要这样做。查询不得引起副作用。带有副作用的简单查询可能会起作用,但是当您将它们变得稍微复杂时,它们就会开始以奇怪的方式中断。
  • @AaronM.Eshbach BTW,data.AsParallel().Aggregate 也可能不起作用:)
  • @zcui93 好点!此外,Aggregate 会在内部创建包含所有 new { ... } 的 GC 垃圾,并且效率低下,因为无法提前退出循环。很快,标准 LINQ 不适合此类任务。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多