none
LINQ OrderBy, ThenBy Объясните работу методов сортировки на примере решения конкретной задачи. RRS feed

  • Вопрос

  • Даны последовательности положительных целых чисел A и B; все числа в каждой последовательности различны. Найти внутреннее объединение A и B (см. LinqBegin46), пары в котором должны удовлетворять следующему условию: последняя цифра первого элемента пары (из A) должна совпадать с первой цифрой второго элемента пары (из B). Представить найденное объединение в виде последовательности строк, содержащих первый и второй элементы пары, разделенные двоеточием, например, «49:921». Порядок следования пар должен определяться исходным порядком элементов последовательности A, а для равных первых элементов пар — лексикографическим порядком строковых представлений вторых элементов (по возрастанию).

    Мое решение не дает правильной сортировки:

    int[] a = new int[4]{2, 62, 3, 7};

    int[] b = new int[4]{28, 352, 22, 4};
    var res = a.Join(b,
                               e => e % 10,
                               p => (int)Char.GetNumericValue(p.ToString()[0]),
                               (e, p) => { return "" + e + ":" + p; })
                     .OrderBy(e => e)
                     .ThenBy(e => e.Split(':')[1]);
     foreach (var elem in res)
            Console.Write(elem + "     ");
    Суть вопроса - как в результирующей последовательности оставить исходный порядок элементов по массиву "а"(по части строки до двоеточия) а после этого, идущие подряд одинаковые элементы отсортировать по части строки идущей после двоеточия в лексикографическом порядке ?


    • Изменено JustAndre 1 декабря 2016 г. 11:44
    1 декабря 2016 г. 11:39

Ответы

  • Добрый день.

    У вас сейчас результат Join строка. Если вам нужно сохранить порядок из исходной коллекции, то... Это просто не получится. Если вам надо отсортировать по тому, что идет до двоеточия, то я бы советовал в результате Join возвращать не строку, а объект с двумя полями e и p. Если хотите. OrderBy будет по e, а ThenBy по p. Ну а после сортировок, уже можно будет добавить Select который преобразует объект с двумя полями в строку нужного вам вида.

    2 декабря 2016 г. 11:02
    Отвечающий
  • Уже не совсем в тему поста, но в решении данного вопроса мне помогла замена Join на GroupJoin: var res = a.GroupJoin(b, e => e % 10, p => (int)Char.GetNumericValue(p.ToString()[0]), (e, p) => new{ firstNum = e, secondNums = p.Select(i => i).OrderBy(i => i.ToString()) } );
    6 декабря 2016 г. 15:11

Все ответы

  • Добрый день.

    У вас сейчас результат Join строка. Если вам нужно сохранить порядок из исходной коллекции, то... Это просто не получится. Если вам надо отсортировать по тому, что идет до двоеточия, то я бы советовал в результате Join возвращать не строку, а объект с двумя полями e и p. Если хотите. OrderBy будет по e, а ThenBy по p. Ну а после сортировок, уже можно будет добавить Select который преобразует объект с двумя полями в строку нужного вам вида.

    2 декабря 2016 г. 11:02
    Отвечающий
  • Спасибо за ответ!
    2 декабря 2016 г. 11:05
  • Уже не совсем в тему поста, но в решении данного вопроса мне помогла замена Join на GroupJoin: var res = a.GroupJoin(b, e => e % 10, p => (int)Char.GetNumericValue(p.ToString()[0]), (e, p) => new{ firstNum = e, secondNums = p.Select(i => i).OrderBy(i => i.ToString()) } );
    6 декабря 2016 г. 15:11
  • А теперь в тему топика:

    var res = a.Join(
                    b.OrderBy(e => e),
                    e => e[0],
                    p => p[0],
                    (e, p) => new
                    {
                        first = e,
                        second = p
                    }).Join(
                    c.OrderByDescending(e => e),
                    d => d.first[0],
                    f => f[0],
                    (d, f) => new
                    {
                        first = d.first,
                        second = d.second,
                        third = f
                    });

    10 декабря 2016 г. 15:11