Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficient way to get first missing element in ordered sequence?

I have an ordered sequence like {1, 3, 5, 6, 8, 9} I want to get first missing element(2 in the example) or max() if sequence contains no missing elements. Now I'm doing it like this:

public static int GetRegisterNumber<T>(this IQueryable<T> enumerable, Func<T, bool> whereFunc, Func<T, int?> selectFunc)
{
    var regNums = enumerable.OrderBy(selectFunc).Where(whereFunc).ToArray();

    if (regNums.Count() == 0)
    {
        return 1;
    }

    for (int i = 0; i < regNums.Count(); i++)
    {
        if (i + 1 != regNums[i])
        {
            return regNums[i].Value + 1;
        }
    }

    return regNums.Last().Value + 1;
}

But i think there are much faster methods. Any suggestions?

like image 869
xumix Avatar asked Jul 08 '09 14:07

xumix


People also ask

How do you find the missing number in a sequence?

Step 1: Find the common difference of each pair of consecutive terms in the sequence by subtracting each term from the term that comes directly after it. Step 2: Add the common difference to the number prior to the first missing number in the sequence. Step 3: Repeat Step 2 for any other missing numbers.

How do you find the missing element in a set?

Simple Approach So the sum of n elements, that is the sum of numbers from 1 to N can be calculated by using the formula N * (N + 1) / 2. Now find the summation of all elements in the array and subtract it from the summation of first N natural numbers, the value obtained will be the value of the missing element.

How do you find the missing number in an array of 1 to 100?

Now, sum of natural numbers from 1 to N, can be expressed as Nx(N+1)/2 . In your case N=100. Subtract the sum of the array from Nx(N+1)/2 , where N=100. That is the missing number.

How do you find the missing number in an array that contains integers from 1 to n?

Find the sum of the numbers in the range [1, N] using the formula N * (N+1)/2. Now find the sum of all the elements in the array and subtract it from the sum of the first N natural numbers. This will give the value of the missing element.


2 Answers

Edit: I just noticed that enumerable is IQueryable<T> but selectFunc and whereFunc are of type Func<T, _>. This will cause the Enumerable versions of OrderBy and Where to be called, rather than using database calls. You probably want to switch them to Expression<Func<T, _>> instead.

If you don't want to order regNums first, here's a O(n) golf-style solution:

var max = regNums.Max(i => (int?)i) ?? 0;
return Enumerable.Range(1, max + 1)
                 .Except(regNums)
                 .Min();

By line:

  1. By casting to int?, Max will return null if regNums is empty, coalesced to 0.

  2. Build a sequence of all possible registers, including our next value if full.

  3. Subtract the current set of registers.

  4. Pick the lowest.

like image 161
dahlbyk Avatar answered Nov 08 '22 14:11

dahlbyk


I'd probably look at something like below; the Where can be done outside (as can the selector to be honest):

If you expect to start at 1:

public static int GetRegisterNumber<T>(this IEnumerable<T> enumerable,
    Func<T, int> selectFunc)
{
    int expected = 1;
    foreach (T item in enumerable) {
        if (selectFunc(item) != expected) return expected;
        expected++;
    }
    return expected;
}

To start with the first item in the list:

public static int GetRegisterNumber<T>(this IEnumerable<T> enumerable,
    Func<T, int> selectFunc)
{
    bool first = true;
    int prev = -1;
    foreach (T item in enumerable)
    {
        int val = selectFunc(item);
        if(first) {
            prev = val;
            first = false;
        } else if (val != prev + 1) {
            return prev + 1;
        }
        prev = val;
    }
    return first ? 1 : prev + 1;
}

It isn't clear how you wanted to handle nulls, so I didn't. Note that this only iterates once, and doesn't buffer everything.

like image 44
Marc Gravell Avatar answered Nov 08 '22 12:11

Marc Gravell