Сортировка списка, игнорируя каждый n-й элемент?

У меня есть список (я могу реализовать его, как любой тип коллекции дает сжатое решение) вот так:

4,1,5,2,1,3,8,1,6,4,2,3

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

Я хотел бы отсортировать массив таким образом, чтобы каждое третье значение оставалось на месте. Для примера, который я дал, результатом будет:

1,1,5,1,2,3,2,4,6,4,8,3

Элементы с индексами 0,1,3,4,6 и 7 были отсортированы. Элементы с индексами 2,5 и 8 не были отсортированы.

Другой способ выразить это - представить, что список - это x, x, y, x, x, y, x, x, y, x, x, y, и я хочу сортировать только xs.

Я могу написать алгоритм, но задаюсь вопросом, есть ли лаконичный способ сделать это?

3
добавлено
Просмотры: 1
de
Это может быть более целесообразным при просмотре кода (после того, как вы предложите/напишите алгоритм).
добавлено автор Paul Fleming, источник
@flem Я считаю, но одна из целей SO - учиться и продвигаться вперед? Написание алгоритма тривиально. Моя цель - искать более сжатый подход.
добавлено автор Simon, источник

3 ответы

Если вы отчаянно хотите сделать это действительно эффективно, я бы выбрал решение simple :

  • Извлеките элементы, которые вы хотите отсортировать, в новый список
  • Сортировка списка
  • Создайте новый список, объединяющий элементы, которые вы хотите сортировать, с фиксированными или (если вы предпочитаете использовать измененные коллекции) просто верните отсортированные элементы в исходный список.

Итак, что-то вроде:

var list = ...;//Get hold of the whole list.
var sortedElements = list.Where((value, index) => index % 3 != 2)
                         .OrderBy(x => x)
                         .ToList();
for (int i = 0; i < sortedElements.Count; i++)
{
    int index = (i/2) * 3 + i % 2;
    list[index] = sortedElements[i];
}
2
добавлено
Спасибо, Джон. Первоначальные комментарии (после удаления) попросили меня «показать мне, что вы сделали в первую очередь», и я был настолько расстроен, что начал писать алгоритм. Я собираюсь протестировать, когда увижу этот ответ, но теперь я могу перейти от двух фугорных кодов для , построив 2 списка, а затем перейдя на более элегантный подход, который я искал. Еще раз спасибо, я чему-то научился и получил новый инструмент! :)
добавлено автор Simon, источник

Попробуйте следовать linq

var ints = new int[]{4,1,5,2,1,3,8,1,6,4,2,3};
var result = ints.Where((i,j) => j%3!= 2).OrderBy(i=>i).ToArray();

var index = ints.Select ((i , j)=> 
    {
        if (j%3==2) 
            return i; 
        else 
            return result[(j/3)*2 + j%3];
    });

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

1
добавлено
Он Джон, а не Иоанн. Ответьте также на ответ. Всегда приятно иметь несколько ответов, и это красота форума.
добавлено автор Tilak, источник
Спасибо. Хотел бы я принять 2 ответа. Мне нравится использование LINQ здесь, но я думаю, что решение Джона Скита легче читать (наверняка, в один прекрасный день кому-то придется это прочитать). По этой причине я принимаю решение Джона и поддерживаю ваше. Еще раз спасибо.
добавлено автор Simon, источник

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

numbers.Where((n, index) => (index + 1) % 3 == 0);
numbers.Where((n, index) => (index + 1) % 3 != 0);

Это дает вам списки индексов thrid и то, что нужно сортировать.

0
добавлено