Отсортировать данные через LINQ

В общем у меня есть список нужно обработать данные и получить на выходе такие данные, только есть условие, нужно сделать через Linq. Данные могут быть записаны хаотично, то есть записей с null может и не быть, картинка это просто пример логики

введите сюда описание изображения


Ответы (2 шт):

Автор решения: default locale

Ну, если я правильно понял, то можно с помощью LINQ написать так:

var input = new Dictionary<string, string>
{
    {"1", "10"},
    {"2", "20"},
    {"3", "30"},
    {"4", "40"},
    {"5", null},
    {"7", null},
    {"8", "50"}
};
//преобразуем ключи в int
var intKeys = input
    .Select(item => new {Key = int.Parse(item.Key), item.Value})
    .ToList();
var notNulls = intKeys
    //отфильтровываем нули
    .Where(item => item.Value != null)
    //сортируем
    .OrderBy(item => item.Key)
    .ToList();
var result = notNulls
    //сливаем список с самим собой чтобы получить пары (текущий, следующий)
    .Zip(notNulls
            //сдвигаем на 1
            .Skip(1)
            //добавляем фиктивный элемент максимум+1 в конце, чтобы у всех элементов была пара
            .Concat(Enumerable.Repeat(new {Key = intKeys.Max(i => i.Key) + 1, Value = ""}, 1)),
        //собираем диапазон
        (current, next) => new
        {
            //если есть промежуток со следующим, то составляем диапазон [текущий;следующий-1]
            //если нет, то в качестве ключа текущий элемент
            Key = current.Key + 1 == next.Key ? $"{current.Key}" : $"{current.Key}-{next.Key - 1}",
            current.Value
        }
    );
//ToDictionary или ToLookup по вкусу
foreach (var v in result)
{
    Console.WriteLine($"{v.Key}, {v.Value}");
}

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

→ Ссылка
Автор решения: Alexander Petrov

нужно сделать через Linq

Не нужно.
Каждому инструменту - своё предназначение. В данном случае цели можно достичь за один проход по коллекции.
Конечно, с десятком элементов это не важно. Но на больших объёмах может быть критично.

var items = new List<KeyValuePair<string, string>>
{
    new("1", "10"),
    new("2", "20"),
    new("3", "30"),
    new("4", "40"),
    new("5", null),
    new("7", null),
    new("8", "50"),
    new("9", null)
};

var result = new List<KeyValuePair<string, string>>();

for (int i = 0; i < items.Count; i++)
{
    if (items[i].Value != null)
    {
        int j = i + 1;
        if (j < items.Count && items[j].Value == null)
        {
            while (j < items.Count && items[j].Value == null)
            {
                j++;
            }

            string key = items[i].Key + "-" + items[j - 1].Key;
            result.Add(new KeyValuePair<string, string>(key, items[i].Value));
            i = j - 1;
        }
        else
        {
            result.Add(items[i]);
        }
    }
}

foreach (var item in result)
    Console.WriteLine(item);

Если вместо индексируемого списка имеется какая-либо другая коллекция, думаю, не составит труда преобразовать её: .OrderBy(...).ToList(). Конечно, это добавит накладные расходы. Поэтому стоит изначально подумать о правильном выборе подходящей коллекции.

→ Ссылка