【问题标题】:Tough Linq Query艰难的 Linq 查询
【发布时间】:2010-09-14 00:33:51
【问题描述】:

我有一个 IEnumerable 发票,这些发票有行项目。这些订单项具有优先级。我正在编写各种策略来自动将现金应用于这些行项目,其中一个给我带来了一些麻烦。我的模式是准备一个 linq 语句来订购发票的行项目,然后遍历 linq 查询,按顺序应用现金,直到我用完为止。

这个 linq 语句的一个例子是最简单的策略,按优先级和到期日支付每个行项目,如下所示:

from lineItem in invoices.SelectMany(invoice => invoice.LineItems)
orderby lineItem.Priority, lineItem.DueDate
select lineItem;

其中一种策略是按优先级顺序将现金应用于具有给定优先级的最旧的剩余项目,然后移至每个优先级的下一个最旧的项目。

编辑:如何开始我要求的查询的示例 -

from lineItem in invoices.SelectMany(invoice => invoice.LineItems)
group lineItem by lineItem.Priority into priorities
orderby priorities.Key
select priorities.OrderBy(item => item.DueDate);

我们现在有具有相同优先级的订单项“桶”,在桶中按截止日期排序。我需要从每个存储桶中提取第一个项目,然后是第二个,等等,直到我订购了所有项目。我想纯粹在 linq 中执行此排序。

谁能想出一种完全在 linq 中表达这一点的方法?

【问题讨论】:

  • 你刚刚做到了!你在问你的查询还没有做什么?
  • @Timwi - 我认为该示例显示了一个简化的策略 - 实际所需的策略总结在代码下方的单个段落中。 @marr75 如果您能给我们一个具体的例子,那将非常有帮助 - 例如一些例子 LineItems 以及使用新策略应该购买它们的顺序。
  • 第一个查询完全按照段落所述进行。第二个查询(在“编辑”之后)做了一些看起来没有必要的花哨的分组。
  • @Timwi 对于更简单的策略,是的,第一个示例完全符合要求。我得出的结论是,为了做我需要做的事情,我必须在我在分组中创建的存储桶中模仿 row_order(组内的排名),然后我将按此排名然后按优先级排序。谁能想到一个更优雅的解决方案?
  • @Timwi - 我不认为确实如此。它读起来就像 - 支付优先级 1 中最旧的项目,然后支付优先级 2 中最旧的项目,然后优先级 3 中最旧的项目,然后优先级 1 中的下一个最旧项目,等等。这与第一个示例不同。但是,我什至不确定这是否正确,这就是为什么我要一个具体的例子。

标签: c# linq


【解决方案1】:

我不知道您将如何将其归结为比您拥有的更好的查询,也许嵌套 from 查询以自动执行 SelectMany

var proposedPayments = new List<LineItem>();
decimal cashOnHand = ...;
var query = invoices.SelectMany(iv => iv.LineItems)
                    .GroupBy(li => li.Priority)
                    .SelectMany(gg =>
                         gg.OrderBy(li => li.DueDate)
                           .Select((li,idx) => Tuple.Create(idx, gg.Key, li)))
                    .OrderBy(tt => tt.Item1)
                    .ThenBy(tt => tt.Item2)
                    .Select(tt => tt.Item3);
foreach (var item in query)
{
    if (cashOnHand >= item.Cost)
    {
        proposedPayments.Add(item); 
        cashOnHand -= item.Cost;
    }

    if (cashOnHand == 0m) break;
}

编辑:已更新以匹配作者想要的段落。被选为每个优先级的第一个。

【讨论】:

  • 同意,我给出的示例查询很好,我可能不太清楚,我需要一个查询来表达我在后面段落中所说的顺序。
  • 是的,这就是我最终得到的结果。我没有使用元组,而是使用匿名类型(调用属性 Rank 增加了可读性)。感谢 StackOverflow 一直陪伴在我身边。
【解决方案2】:

LINQ = 语言集成查询而不是语言集成过程代码。

如果您想要一个查询返回您需要将付款应用到的行项目,那么这是可行的(请参阅.Aggregate),但如果您想实际将资金应用到行项目,那么foreach 循环是一个很好的结构。

http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx

【讨论】:

  • 是的,我知道,我可以在订购订单项后应用 foreach 循环,这样副作用就很明显了。我正在寻找的是一种表达我讨论过的第二个策略的顺序的方法。
  • @marr75:“第二种策略”和你已经编码的那个有什么区别?在我看来,您现有的查询应该可以工作......
  • 这是一个细微的区别,如果添加的示例有助于明确区分,请告诉我。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多