1

I have a collection "cases" (IEnumerable<IPublishedContent>), which I would like to split into chunks like the following, where each second row contains two columns:

<div class="row">
   <div class="col">1</div>
</div>
<div class="row">
   <div class="col">2</div>
   <div class="col">3</div>
</div>
<div class="row">
   <div class="col">4</div>
</div>
<div class="row">
   <div class="col">5</div>
   <div class="col">6</div>
</div>

I have seen different approaches using extension methods, e.g. .Chunk(2), .Batch(2) or .Split(2), but mostly where it is splitted into fixed sizes e.g. [1,2], [3,4], [5,6], [7]

For now I have the following:

var batches = w
            .Select((x, i) => new { x, i })
            .GroupBy(p => (p.i / (p.i % 2 == 0 ? 2 : 1)), p => p.x);

var rows = batches;
var count = 0;
foreach (var row in rows)
{
   <div class="row">
       @foreach (var c in row)
       {
           <div class="col">@(count+1)</div>
           count++;
       }
    </div>
}

When the collection contains 7 elements, the output is:

<div class="row">
   <div class="col">1</div>
</div>
<div class="row">
   <div class="col">2</div>
   <div class="col">3</div>
</div>
<div class="row">
   <div class="col">4</div>
   <div class="col">5</div>
</div>
<div class="row">
   <div class="col">6</div>
</div>
<div class="row">
   <div class="col">7</div>
</div>

Any suggestion how I can get the output as in the first example?

bjarne_f
  • 105
  • 1
  • 2
  • 12
  • Why are you dividing? You just really need p.1 % 2. – jdweng Jan 05 '17 at 12:20
  • No, that tried that too, which splitted the collection into two group - first one with 4 and second one with 3. So the output rendered two rows, which 4 columns in first row and 3 columns in second row. – bjarne_f Jan 05 '17 at 12:32
  • Then you want to divide by 2 : p => (int)(p.i/2) – jdweng Jan 05 '17 at 12:42
  • It was similar to this http://stackoverflow.com/a/24087164/1693918 but I didn't want equal chunks sizes, but rather 1, 2, 1, 2,.. chunks per group. – bjarne_f Jan 05 '17 at 12:48
  • Isn't 1,2; 1,2; 1,2; two groups? 1,2 are the two items in each row. So if you enumerate through the groups you get your results. – jdweng Jan 05 '17 at 12:53
  • @jdweng it was also what I did first, but that returns chunks of 2 items per group .. and with 7 elements, then 1 item in last group. – bjarne_f Jan 05 '17 at 12:53
  • Yes, but `.GroupBy(p => p.i / 2, p => p.x);` returns [1,2], [3,4], [5,6], [7] I need: [1], [2,3], [4], [5, 6], [7], etc. – bjarne_f Jan 05 '17 at 12:57
  • You should only get four groups, not seven. You are doing something wrong if you are getting 7 groups. 0/2 and 1/2 = 0; 2/2 and 3/2 = 1; 4/2 and 5/2 = 2; 6/2 = 3. So your groups are 0,1,2,3. You may be getting confused because your columns are starting a 1 while the indexing starts at zero. – jdweng Jan 05 '17 at 13:02
  • The brackets marks the group. So having 7 elements in the collection: When using `.GroupBy(p => p.i / 2, p => p.x)` it returns two groups with 4 items in first and 3 items in second. When using `.GroupBy(p => p.i / 2, p => p.x)` it returns four groups with 2 items in each of the first 3 groups and 1 item in last group: [1,2], [3,4], [5,6], [7] – bjarne_f Jan 05 '17 at 13:05
  • It was not an issue to split into chunks of equal sizes, but when it should returns different items in each group. But the answer posted by @Ivan Stoev solved it. – bjarne_f Jan 05 '17 at 13:10

1 Answers1

2

I believe you can use GroupBy with composite key first to split the input to triples and then to split the triple to pair:

var batches = w.Select((x, i) => new { x, i })
    .GroupBy(e => new { K1 = e.i / 3, K2 = e.i % 3 == 0 ? 0 : 1 })
    .Select(g => g.Select(e => e.x).ToArray())
    .ToList();

Another way would be to produce a single grouping key using the same idea:

.GroupBy(e => 2 * (e.i / 3) + (e.i % 3 == 0 ? 0 : 1))
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343