开发者

Tough Linq Query

I have an IEnumerable of invoices, these invoices have line items. These line items have a priority. I'm programming a variety of strategies to automatically apply cash against these line items and one is giving me some trouble. My pattern has been to prepare a linq statement to order the line items of the invoices then iterate over the linq query applying cash in order until I run out.

An example of this linq statement for the simplest strategy, pay each line item by priority and due date, is shown below:

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

One of the strategies is to apply cash to the oldest remaining item with a given priority, in priority order, then move to the next oldest of each priority.

EDIT: Example of how one might start the query I'm asking for -

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

We now have "buckets" of line items with the same priority, ordered by due date within the bucket. I need to extract the first line item from each bucket, followed by the second, etc. until I have ordered all of the items. I would like to perform this ordering purely in linq.

Can anyone think of a way to express this entirely in linq?


I don't see how you'll get this down to a better query than what you have, perhaps nest from queries to automatically do the 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;
}

Edit: updated to match the paragraph the author wanted. Selected as first of each priority.


LINQ = Language Integrated QUERY not Language Integrated PROCEDURAL CODE.

If you want a query that returns the line items you need to apply the payment to, then that's do-able (see .Aggregate), but if you want to actually apply the money to the line items as you go, then a foreach loop is a fine construct to use.

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜