Search code examples
c#linqmorelinq

How can I check that a sequence of indices of type int are contiguous?


I have a Column class which has an Index property of type int.

If I have a collection of Column objects, I am looking for a way to test if their indices are contiguous. By contiguous I mean that the indices are next to each other, so if ordered by value they are 1 apart from the next and previous Index.

There can be any number of column objects.

So, for example:

  • 10,11,12,13 => true

  • 3,5,7 => false

  • 1,2,4 => false

Edit

While these examples are of ordered indices, I would like a solution that takes an unordered set of indices.

I feel sure there is probably a neat Linq way of solving this, but I cannot see it.

Expressed in code:

public class Column 
{
    public int Index { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        // Example set of columns 1
        List<Column> columns1 = new List<Column>()
        {
            new Column(){Index = 10},
            new Column(){Index = 11},
            new Column(){Index = 12},
            new Column(){Index = 13},
        };

        // Example set of columns 2
        List<Column> columns2 = new List<Column>()
        {
            new Column(){Index = 3},
            new Column(){Index = 5},
            new Column(){Index = 7},
        };

        // Example set of columns 3
        List<Column> columns3 = new List<Column>()
        {
            new Column(){Index = 1},
            new Column(){Index = 2},
            new Column(){Index = 4},
        };

        var result1 = IndicesAreContiguos(columns1); // => true
        var result2 = IndicesAreContiguos(columns2); // => false
        var result3 = IndicesAreContiguos(columns3); // => false
    }

    public bool IndicesAreContiguos(IEnumerable<Column> columns) 
    {
        // ....???
    }

}

Solution

  • Give this a go:

    public static bool IndicesAreContiguos(IEnumerable<Column> columns)
    {
        var ordered = columns.Select(x => x.Index).OrderBy(x => x).ToArray();
        return ordered.Skip(1).Zip(ordered, (x, y) => x - y).All(z => z == 1);
    }
    

    This is literally "ordered by value they are 1 apart from the next and previous Index."