Как перетасовать список, кроме элемента?
У меня есть список целых чисел с элементами value: 0, 7, 2, 1, 6, 5.
Я знаю, что могу использовать метод
Collections.shuffle(list);
Чтобы перетасовать мой список. Но я не хочу менять значение 2-й позиции. Это должно быть всегда 7.
Как я могу это сделать ?
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]