Можно ли использовать LINQ для поиска пробелов в отсортированном списке? - PullRequest
24 голосов
/ 24 ноября 2010

Могу ли я использовать LINQ таким образом, чтобы я мог определить, что "9" первое пропущенное значение в отсортированном списке без использования цикла for и сравнения каждого значения с соседним с ним?

var listStringVals = new [] { "7", "13", "8", "12", "10", "11", "14" };
// sort list to "7","8","10","11","12","13","14"
var sortedList = listStringVals.OrderBy(c => int.Parse(c)).ToList();
// need some magic here to get the first gap in the sorted list

Ответы [ 7 ]

59 голосов
/ 24 ноября 2010

Пусть

var strings = new string[] { "7", "13", "8", "12", "10", "11", "14" };

Тогда

var list = Array.ConvertAll(strings, s => Int32.Parse(s)).OrderBy(i => i);
// or
var list = strings.Select(s => int.Parse(s)).OrderBy(i => i);
// or
var list = strings.OrderBy(s => int.Parse(s));

(примечание это вопрос)

, а затем

var result = Enumerable.Range(list.Min(), list.Count).Except(list).First(); // 9
// or
int min = list.Min(), max = list.Max();
var result = Enumerable.Range(min, max - min + 1).Except(list).First();
11 голосов
/ 24 ноября 2010

Вот способ начать работу (здесь я использовал int значения):

List<int> listStringVals = (new int[] { 7, 13, 8, 12, 10, 11, 14 }).ToList();
List<int> SortedList = listStringVals.OrderBy(c => c).ToList();
List<int> Gaps = Enumerable.Range(SortedList.First(), 
                                  SortedList.Last() - SortedList.First() + 1)
                           .Except(SortedList).ToList();
4 голосов
/ 24 ноября 2010
var listStringVals = new string[] {"7", "13", "8", "12", "10", "11", "14"};
var sortedInts = listStringVals.Select(c => int.Parse(c)).OrderBy(x => x);
var noGaps = Enumerable.Range(sortedInts.First(), 
                              sortedInts.Last() - sortedInts.First() + 1);
var missing = noGaps.Except(sortedInts).Select(x => x.ToString()).First();

Редактировать: генерация фиксированного диапазона благодаря Ответу BeemerGuy . Все еще покидаю мою, так как она не игнорирует уродливость списка string представлений int s:)

3 голосов
/ 24 ноября 2010
string firstGap = sortedList
    .Zip(sortedList.Skip(1), (f, s) => Tuple.Create(f, s))
    .First(tup => (int.Parse(tup.Item1) + 1) != int.Parse(tup.Item2)).Item1;

Должен дать вам первый элемент перед первым пробелом, поэтому первый отсутствующий элемент:

string gap = (int.Parse(firstGap) + 1).ToString();
3 голосов
/ 24 ноября 2010

(Абатищев опередил меня, но его ответ в любом случае лучше. Однако, поскольку альтернативные решения одной и той же проблемы могут быть забавными, я все еще публикую это.)

Взломать взломать взломать.Но работает, если вы действительно хотите сделать это.Производительность будет ужасной, потому что этот метод не остановится, когда он найдет ответ - он всегда будет проходить по каждому номеру!Но это будет работать:

public static int FindFirstMissing(IEnumerable<int> sequence)
{
    bool found = false;

    int agg = sequence.Aggregate((aggregate, next) => {
        if (found)
            return aggregate;

        if (next - aggregate != 1) {
            found = true;
            return aggregate + 1;
        }

        return next;
    });

    if (!found)
        throw new ArgumentException("sequence", "Contains no missing numbers.");

    return agg;
}
1 голос
/ 25 ноября 2010

Уже немного поздно, но я думаю, что это крутой способ сделать это:

List<int> listStringVals = (new int[] { 7, 13, 8, 12, 10, 11, 14 }).ToList();
            listStringVals.Sort();
            return listStringVals.Skip(1).Select((x, i) => x - listStringVals[i] == 1).Any(x => !x);
0 голосов
/ 17 декабря 2012

Почему бы просто не использовать All, поскольку все члены коллекции должны соответствовать критериям ...

Пример

someVar.All(v => someVar.Contains(v + 1) || v == someVar.Last())

Тогда вам не нужно заказывать, и это лучше.

Вы могли бы отсортировать после этого шага или даже во время, если вам нужно, но я лично просто использовал бы отсортированную коллекцию и сделал бы, чтобы она работала для меня.

Вы могли бы получить значения, если вам нужно, после выполнения проверки, а затем вернуть результат проверки или скрыть его, если вы хотите по какой-то причине, через многострочную модификацию, приведенную выше, вместе со списком для хранения значений.

, например

someVar.All((v) => { 
    bool result = someVar.Contains(v + 1) || v == someVar.Last();
    if(!result) someList.Add(v);
    return true;
});

Проверка счетчика списка (который можно заказать) для ненулевого значения, чтобы указать, удовлетворяет ли оно или нет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...