uso del hecho de que una lista se retire rápido e insertar:
- elementos Enumerar fija y copiarlos y su índice
- elementos fijos de borrado de la lista
- aleatoria restante subconjunto
- put elementos fijos de vuelta en
Ver https://stackoverflow.com/a/25233037/3449962 para una solución más general.
Esto utilizará operaciones in situ con sobrecarga de memoria que depende de la cantidad de elementos fijos en la lista. Lineal en el tiempoUna posible implementación de shuffle_subset
:
#!/usr/bin/env python
"""Shuffle elements in a list, except for a sub-set of the elments.
The sub-set are those elements that should retain their position in
the list. Some example usage:
>>> from collections import namedtuple
>>> class CAnswer(namedtuple("CAnswer","x fixed")):
... def __bool__(self):
... return self.fixed is True
... __nonzero__ = __bool__ # For Python 2. Called by bool in Py2.
... def __repr__(self):
... return "<CA: {}>".format(self.x)
...
>>> val = [3, 2, 0, 1, 5, 9, 4]
>>> fix = [2, 5]
>>> lst = [ CAnswer(v, i in fix) for i, v in enumerate(val)]
>>> print("Start ", 0, ": ", lst)
Start 0 : [<CA: 3>, <CA: 2>, <CA: 0>, <CA: 1>, <CA: 5>, <CA: 9>, <CA: 4>]
Using a predicate to filter.
>>> for i in range(4): # doctest: +NORMALIZE_WHITESPACE
... shuffle_subset(lst, lambda x : x.fixed)
... print([lst[i] for i in fix], end=" ")
...
[<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>]
>>> for i in range(4): # doctest: +NORMALIZE_WHITESPACE
... shuffle_subset(lst) # predicate = bool()
... print([lst[i] for i in fix], end=" ")
...
[<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>]
"""
from __future__ import print_function
import random
def shuffle_subset(lst, predicate=None):
"""All elements in lst, except a sub-set, are shuffled.
The predicate defines the sub-set of elements in lst that should
not be shuffled:
+ The predicate is a callable that returns True for fixed
elements, predicate(element) --> True or False.
+ If the predicate is None extract those elements where
bool(element) == True.
"""
predicate = bool if predicate is None else predicate
fixed_subset = [(i, e) for i, e in enumerate(lst) if predicate(e)]
fixed_subset.reverse() # Delete fixed elements from high index to low.
for i, _ in fixed_subset:
del lst[i]
random.shuffle(lst)
fixed_subset.reverse() # Insert fixed elements from low index to high.
for i, e in fixed_subset:
lst.insert(i, e)
if __name__ == "__main__":
import doctest
doctest.testmod()
[? ¿Qué has intentado] (http://mattgemmell.com/2008/12/08/what-have-you-tried/) –
que he intentado dos enfoques - primero usando solo random.shuffle() y luego restaurando ciertos elementos en sus posiciones originales. Otro consistió en usar random.choice para elementos que se aleatorizaron, o seleccionar ciertos elementos para elementos "congelados". Sin embargo, ambos enfoques parecen ser un poco poco elegantes, y definitivamente no pitónicos. –