Создать последовательность в Linq

Я хочу сгенерировать последовательность с Linq, которая идет от 10 до 100 с размером шага 10. Последовательность также должна содержать пользовательское значение (в правильном порядке).

Это то, что у меня есть сейчас, и мне интересно, есть ли более разумный способ сделать это с помощью выражений Linq.

var pageSize = 25; //number that must be in sequnce if not already, can be anything.
var items = Enumerable.Range(10, 100)     //Generate range           
           .Where(x => x % 10 == 0)       //Take every 10th item
           .Concat(new[] { pageSize })    //Add the custom number
           .Distinct()                    //If the custom number was already in there, remove it
           .OrderBy(x => x);              //Sort the sequence

Результат:

10 
20 
25 
30 
40 
50 
60 
70 
80 
90 
100 
11 голосов | спросил Magnus 16 AMpWed, 16 Apr 2014 11:45:38 +040045Wednesday 2014, 11:45:38

4 ответа


3

Знайте свою библиотеку

.Distinct() должен немедленно заставить вас подумать о Set
.OrderBy(...) сильный > должен заставить вас подумать о сортированной коллекции.

Я вам даю: SortedSet<T> , часть .NET с версии 4.0.

Когда LINQ недостаточно, увеличьте его

LINQ использует методы расширения , поэтому, если он не иметь то, что вам нужно, добавить свой собственный:

private static IEnumerable<T> ToSelectionWith<T>(this IEnumerable<T> sequence, params T[] items)
{
    return new SortedSet<T>(sequence.Concat(items));
}

Использование

Это позволяет вам называть его так, как если бы он был частью LINQ:

var pageSize = 25;
var items = Enumerable.Range(1, 10).Select(x => x*10).ToSelectionWith(pageSize);

Преимущества

  1. Это краткий - однострочный. Вы даже можете пропустить метод расширения и напрямую использовать SortedSet.
  2. Он доступен для чтения - путем его обертывания в методе расширения, уточняется намерение использовать код SortedSet.
  3. Он хорошо работает - в моем грубом тесте Stopwatch, он разбил ваши версии и Sandeep для небольшого и большого ввода последовательности. (В частности, подход SortedSet выполняется в два раза быстрее, чем версия Sandeep для вашего исходного ввода, и по крайней мере в три раза быстрее для очень больших размеры ввода).
ответил Adam 17 AMpThu, 17 Apr 2014 06:10:50 +040010Thursday 2014, 06:10:50
8

Размер исходного списка в следующем коде меньше:

var x = Enumerable.Range(1, 10)
                  .Select(x_ => x_ * 10)
                  .Concat(new[] {25})
                  .Distinct()
                  .OrderBy(x_ => x_)
                  .ToList();

В противном случае ваш оригинальный код будет идеальным.

ответил Sandeep 16 PMpWed, 16 Apr 2014 12:13:26 +040013Wednesday 2014, 12:13:26
5

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

var pageSize = 25;

var items =
  Enumerable.Range(10, 91)           
  .Where(x => x % 10 == 0 || x == pageSize);

Примечание. Это естественно работает только в том случае, если пользовательское значение находится внутри диапазона.

ответил Guffa 16 PMpWed, 16 Apr 2014 13:03:07 +040003Wednesday 2014, 13:03:07
1

Несмотря на то, что добавленный фактический вариант использования OP не имеет большого значения, учитывая общую проблему вставки значения в правильном порядке в упорядоченной последовательности , более эффективное время и пространство решение существует.

public static IEnumerable<T> InsertPreservingOrder<T> (this IEnumerable<T> sortedSequence, T value)
    where T : IComparable<T>
{
    return sortedSequence.TakeWhile(x => x.CompareTo(value) < 0)
             .Append(value)
             .Concat(sortedSequence.SkipWhile(x => x.CompareTo(value) <= 0));
}

где Append - синтаксический сахар для .Concat(new{...}) в соответствии с ответом @ codeparkle :

public static IEnumerable<T> Append<T>(this IEnumerable<T> sequence, params T[] items)
{
    return sequence.Concat(items);
}

Эта операция имеет постоянное (O (1)) пространство, линейное (O (n)) время и ленивое. Особенно полезно в таких ситуациях:

var customValue = 15;
var defaultValues = Enumerable.Range(1, 10000000).Select(x_ => x_ * 10);
var items = defaultValues.InsertPreservingOrder(customValue);
// then later
items.Take(10).ToList().ForEach(Console.WriteLine);

Я также думаю, что этот метод является явным улучшением в захвате намерений программиста w.r.t. в оригинальной версии, независимо от асимптотической сложности. Это подтверждает идею; поэтому его можно использовать повторно, когда текущее значение переменной будет добавлено в набор параметров по умолчанию. Его имя ясно указывает как предварительное условие, что первый параметр считается уже отсортированным, и постусловие, в котором также сортируется возвращаемое значение. Однако это оставляет непрозрачным условие отчетливости.

Хотя я бы предпочел простой defaultValues.Append(customValue).ToSortedSet()

ответил abuzittin gillifirca 17 PMpThu, 17 Apr 2014 18:13:12 +040013Thursday 2014, 18:13:12

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132