-4

Does Anyone know how to do this using C#? It's a coding challenge I have for a class.

Q: array of arrays. Group the input integers into sets that are contiguous in the input array.

e.g.

[1, 2, 3, 5, 6, 8, 9, 10] => [ [1, 2, 3], [5, 6], [8, 9, 10] ]
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
mortis
  • 5
  • 1
    Have you tried anything? https://stackoverflow.com/help/how-to-ask – Slava Knyazev Feb 17 '21 at 03:27
  • So first, sort the array, second, look up how to group consecutive numbers. When you are stuck, show us your code, the pages you researched and where you are stuck. – TheGeneral Feb 17 '21 at 03:39
  • No a problem, feel free to post again. Next time just make sure you add a bit more information about the actual problem. good luck – TheGeneral Feb 17 '21 at 03:45
  • 2
    @00110001 fortunately we already have the code written for almost exactly the same problem (slightly complicated by additional "convert resulting range to string "1-3", hopefully OP will be able to remove those couple lines from the answer). – Alexei Levenkov Feb 17 '21 at 05:08
  • (note that "sorted" may be important for your "coding challenge" - answer posted here and the one I picked as [duplicate](https://stackoverflow.com/questions/4681949/use-linq-to-group-a-sequence-of-numbers-with-no-gaps) do not rely on sequence being sorted. Depending on the goal simple iteration solution may not be accepted also since you need to copy all elements anyway you know that you can't get better than O(n) - so iterating is fine - use that to avoid your teacher's claim it was binary search excersise) – Alexei Levenkov Feb 17 '21 at 05:12

2 Answers2

2

Try this:

public IEnumerable<IEnumerable<int>> ConsecutiveGroups(IEnumerable<int> items)
{
    bool started = false;
    var prev = int.MinValue;

    var curSet = new List<int>();

    foreach(var item in items.OrderBy(x=>x))
    {
        if (item != prev + 1 && started)
        {
            yield return curSet;
            curSet = new List<int>();
        }
        curSet.Add(item);
        started = true;
    }
    yield return curSet;
}
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
0

Here is a solution that uses the Segment operator from the MoreLinq library.

using System;
using System.Linq;
using static MoreLinq.Extensions.SegmentExtension;

public class Program
{
    public static void Main()
    {
        int[] source = new[] { 1, 2, 3, 5, 6, 8, 9, 10 };
        int[][] result = source
            .Segment((current, previous, _) => current != previous + 1)
            .Select(segment => segment.ToArray())
            .ToArray();
        Console.Write($"[{String.Join(", ", source)}]");
        Console.Write($" => ");
        Console.WriteLine($@"[{String.Join(", ", result
            .Select(s => $"[{String.Join(", ", s)}]"))}]");
    }
}

Output:

[1, 2, 3, 5, 6, 8, 9, 10] => [[1, 2, 3], [5, 6], [8, 9, 10]]

Try it on fiddle.

The Segment extension method has the signature below:

public static IEnumerable<IEnumerable<T>> Segment<T>(
    this IEnumerable<T> source,
    Func<T, T, int, bool> newSegmentPredicate);
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104