Как перетасовать список, кроме элемента?


У меня есть список целых чисел с элементами value: 0, 7, 2, 1, 6, 5.

Я знаю, что могу использовать метод

Collections.shuffle(list);

Чтобы перетасовать мой список. Но я не хочу менять значение 2-й позиции. Это должно быть всегда 7.

Как я могу это сделать ?

3 5

3 ответа:

Вы можете перетасовать коллекцию, а затем восстановить 7 на 2-е место:

Collections.shuffle(list);
list.set(list.indexOf(7),list.get(2));
list.set(2,7);

Или короче:

Collections.shuffle(list);
Collections.swap(list, 2, list.indexOf(7));

Как предлагали другие, вы также можете удалить элемент, местоположение которого вы хотите сохранить до перетасовки, и добавить его позже в то же место.

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

Чтобы легко предотвратить перемещение любого количества элементов просто

  • удалить их из списка,
  • перетасовать остальные элементы,
  • верните их в исходное положение (начните слева, чтобы избежать проблем с перемещением элементов вправо).

Есть альтернативное решение, которое длиннее, но, вероятно, быстрее для длинных списков:

public static <T> void shuffleExcept(final List<T> list, final int position) {
    List<T> view = new AbstractList<T>() {
        @Override
        public T get(int index) {
            return list.get(index >= position ? index+1 : index);
        }

        @Override
        public T set(int index, T element) {
            return list.set(index >= position ? index+1 : index, element);
        }

        @Override
        public int size() {
            return list.size()-1;
        }
    };
    Collections.shuffle(view);
}

Здесь мы создаем " вид " исходного списка, который представляет собой весь список, за исключением элемента, который мы хотим сохранить (мы просто сдвигаем индексы последующих элементов). Далее мы перетасуем это представление. В этом вся прелесть интерфейсов: вы можете попросить существующий метод сделать что-то другое, просто передав новую реализацию интерфейса.

Пример использования:

List<Integer> input = Arrays.asList(0, 7, 2, 1, 6, 5);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);
shuffleExcept(input, 1);
System.out.println(input);

Типичный вывод:

[6, 7, 5, 2, 1, 0]
[5, 7, 6, 1, 2, 0]
[6, 7, 2, 0, 5, 1]
[6, 7, 2, 0, 5, 1]
[2, 7, 0, 5, 6, 1]
[6, 7, 0, 2, 5, 1]
[5, 7, 2, 0, 1, 6]