Utilizzare il fatto che l'elenco è rapidamente rimuovere e inserire:
- enumerare fisso elementi e copiare loro e il loro indice di
- di eliminazione elementi fissi da elenco
- riordino rimanente sottoinsieme
- put fisso elementi indietro nel
Vedi https://stackoverflow.com/a/25233037/3449962 per una soluzione più generale.
Questo utilizzerà le operazioni sul posto con sovraccarico della memoria che dipende dal numero di elementi fissi nell'elenco. Lineare nel tempo.Una possibile implementazione di 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()
[? Che cosa hai provato] (http://mattgemmell.com/2008/12/08/what-have-you-tried/) –
che ho provato due approcci - prima usa solo random.shuffle() e poi ripristina determinati elementi nelle sue posizioni originali. Un altro consisteva nell'usare random.choice per gli elementi da randomizzare o selezionare determinati elementi per elementi "congelati". Comunque entrambi questi approcci sembrano essere un po 'poco eleganti, e sicuramente non ptonici. –