1

Using LINQ (or morelinq), How do I divide an unknown length (but small) array into even sets with the smaller (uneven) sets at the end, but maintaining the order within each list?

var array = new int[] {1,2,3,4}; var sets = array.something(3); Looking for a result of: {1,2},{3},{4}

{1} -> {1},{},{}
{1,2} -> {1},{2},{}
{1,2,3} -> {1},{2},{3}
{1,2,3,4} -> {1,2},{3},{4}
{1,2,3,4,5} -> {1,2},{3,4},{5}
{1,2,3,4,5,6} -> {1,2},{3,4},{5,6}

My original code:

const int MaxPerColumn = 6;
var perColumn = (list.Count + columnCount - 1) / columnCount;
for (var col = 1; col <= columnCount; col++)
{
    var items = list.Skip((col - 1) * columnCount).Take(perColumn).Pad(MaxPerColumn, "").ToList();

    // DoSomething
}

which did not work, because with a list of {1,2,3,4} it created {1,2},{3,4},{}

Robert McKee
  • 21,305
  • 1
  • 43
  • 57
  • so why would {1,2,3.4} be {1,2},{3},{4} and {1,2,3,4,5,6} be {1,2}, {3, 4}, {5,6}. The pattern doesn't really line up? – Dispersia Oct 11 '16 at 18:57
  • I think you should explicitly state that your examples are for making 3 groups. – Andrew Morton Oct 11 '16 at 19:09
  • What did you try doing? What problems did you have with your implementation? – Servy Oct 11 '16 at 19:10
  • Are you looking for something like this: [Split List into Sublists with LINQ](http://stackoverflow.com/questions/419019/split-list-into-sublists-with-linq)? – rachri Oct 11 '16 at 19:11
  • 2
    Why do people ask "Using Linq, how do I ...?" Why not just "How do I ...?" Why does it have to use Linq? – user2023861 Oct 11 '16 at 19:15
  • @Servy I'm trying to distribute a list of items across x columns, keeping each list in each column as short as possible. Alphabetized going down then across instead of across then down. – Robert McKee Oct 11 '16 at 19:23
  • @usterdev Something like that, but instead of the list size being fixed, the number of lists is fixed. – Robert McKee Oct 11 '16 at 19:25
  • @RobertMcKee That doesn't answer my questions. I'm not asking you for your requirements, I'm asking you what you implemented in order to meet those requirements and why your implementation didn't work. – Servy Oct 11 '16 at 19:25
  • @Servy, ah. The problem I'm having is with the remainder. My original implementation had issues with 4 elements. It broke it into `{1,2},{3,4},{}` – Robert McKee Oct 11 '16 at 19:26
  • @RobertMcKee Then provide it, and explain, specifically, why it isn't working. – Servy Oct 11 '16 at 19:27
  • @Servy Added my original code, but it was the wrong approach to take, so I didn't even bother to include it. – Robert McKee Oct 11 '16 at 19:33

2 Answers2

1

I suggest not using Linq here, but IEnumerator<T>, not even IEnumerable<T> in the implementation:

public static IEnumerable<T[]> Something<T>(this IEnumerable<T> source, int count) {
  if (null == source)
    throw new ArgumentNullException("source");
  else if (count <= 0)
    throw new ArgumentOutOfRangeException("count");

  int c = source.Count();
  int size = c / count + (c % count > 0 ? 1 : 0);
  int large = count - count * size + c;    

  using (var en = source.GetEnumerator()) {
    for (int i = 0; i < count; ++i) {
      T[] chunk = new T[i < large ? size : size - 1];

      for (int j = 0; j < chunk.Length; ++j) {
        en.MoveNext();

        chunk[j] = en.Current;
      }

      yield return chunk;
    }
  }
}

....

var array = new int[] { 1, 2, 3, 4 };

string result = string.Join(", ", array
  .Something(5)
  .Select(item => $"[{string.Join(", ", item)}]"));

// [1], [2], [3], [4], []
Console.Write(result);
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
1

Here is a linq way

public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int count)
{
    int c = source.Count();
    int chunksize = c / count + (c % count > 0 ? 1 : 0);

    while (source.Any())
    {
        yield return source.Take(chunksize);
        source = source.Skip(chunksize);
    }
}

Based on https://stackoverflow.com/a/6362642/215752 and https://stackoverflow.com/a/39985281/215752

Community
  • 1
  • 1
Hogan
  • 69,564
  • 10
  • 76
  • 117