-2

I have an Object named Item:

public class Item
{
   public Guid Id { get; set; }
   public long Size { get; set; }       
}

in a List<Item>

What I need is to query this list and return a number of rows where the cumulated size (Size property of Item) does not exceed a certain number (threshold).

I could then process these elements, remove them from the original list and get the next elements with the same query until all elements have been processed.

Example List:

Id       Size
----------------
1         10
2         13
3         5
4         30
5         10

Say my desired threshold is a maximum size of 25.

The query should return the items with Id 1 & 2 since their cumulated size doesn't exceed 25. Then I remove these two values. The next time the query should return 3 & 5. Id 4 should never be returned since it exceeds 25.

Any ideas?

SolarX
  • 1,873
  • 2
  • 18
  • 26
  • What you mean by `a number of rows where the cumulated size`? – sll Jan 04 '12 at 15:34
  • 1
    By "cumulated" do you mean the *total* of all the Size property in all the rows picked so far? – Jon Skeet Jan 04 '12 at 15:34
  • 1
    I would just write a loop. There might be a TakeWhile approach, involving an (external) accumulator, but then you're operating outside of the bounds of what Linq is traditionally intended to be. No, I would write a loop and just keep a running sum. – Anthony Pegram Jan 04 '12 at 15:38
  • 1
    LINQ does not seem like a good fit here. Is there a reason why you want to do this with LINQ instead of an old fashion loop? Or is this one of those "LINQ is the best way to deal with collections" things? – cadrell0 Jan 04 '12 at 15:39
  • I know that I could use a loop. But I like the aesthetics of LINQ. So no arguing about taste please ;) – SolarX Jan 04 '12 at 15:46
  • 1
    Regarding your update about including items 3 and 5 and skipping 4, that sounds like a predicate outside of the grouping. For example, if I'm taking items up to a given threshold, then I would naturally return 1 and 2, start over. Hit 3, notice I can't include 4, so return 3 and start over. Then hit 5, etc. If you want 3 and 5 to be together, you would exclude anything like 4 from consideration. `theList.Where(item => item.Size <= maxValue)`. It then makes sense for 3 and 5 to group together, as there is no 4 to get in their way. – Anthony Pegram Jan 04 '12 at 15:52

1 Answers1

0

I think you need to store some running sum value, but TakeWhile should do the job.
Something like this:

var someValues = Enumerable.Range(0, 100);
var runningSum = 0;
var whereSumLessThan100 = someValues.TakeWhile(
    item => { runningSum += item; return runningSum < 100; }).ToList();
foreach(var item in whereSumLessThan100)
    Console.WriteLine(item);
Console.WriteLine("Sum: " + whereSumLessThan100.Sum());
Albin Sunnanbo
  • 46,430
  • 8
  • 69
  • 108