2012-07-29 17 views
5

E 'possibile mischiare solo (continua) parte di una data lista (o matrice in numpy)?Fissare primo elemento, mischiare il resto di un elenco/array

Se questo non è generalmente possibile, come per il caso particolare in cui il primo elemento è fisso mentre il resto della lista/matrice deve essere mescolate? Per esempio, ho una lista/array:

to_be_shuffled = [None, 'a', 'b', 'c', 'd', ...] 

dove il primo elemento deve sempre rimanere, mentre il resto sta per essere mescolate più volte.

Un possibile modo è di mischiare prima l'intera lista e quindi controllare il primo elemento, se non è l'elemento fisso speciale (es. None), quindi scambiare la sua posizione con quella dell'elemento speciale (che richiederebbe quindi una ricerca).

Esiste un modo migliore per fare questo?

risposta

5

array NumPy non copiano i dati al taglio:

numpy.random.shuffle(a[1:]) 
+0

Come ho scelto di implementare usando un array numpy, questa è la soluzione migliore nel mio caso.Altre soluzioni sono anche molto utili e spero che altri le trovino adeguate nei loro rispettivi casi d'uso. – skyork

9

Perché non solo

import random 
rest = to_be_shuffled[1:] 
random.shuffle(rest) 
shuffled_lst = [to_be_shuffled[0]] + rest 
+0

@DavidRobinson, grazie. Il precedente è sul posto, ovvero non esiste una nuova copia di una parte della lista/matrice creata? – skyork

+2

@kojiro 'shuffled_lst' non esiste prima. Probabilmente vuoi dire: 'to_be_shuffled [1:] = rest' – jamylak

+2

@skyork no, sia' shuffled_lst' che 'rest' sono copie (parziali e complete) dei dati in' to_be_shuffled'. – kojiro

3

ho preso la funzione shuffle dal modulo libreria standard random (trovato in Lib\random.py) e modificato leggermente in modo che rimescola solo una parte della lista specificata da start e stop. Lo fa al suo posto. Godere!

from random import randint 

def shuffle(x, start=0, stop=None): 
    if stop is None: 
     stop = len(x) 

    for i in reversed(range(start + 1, stop)): 
     # pick an element in x[start: i+1] with which to exchange x[i] 
     j = randint(start, i) 
     x[i], x[j] = x[j], x[i] 

Per i vostri scopi, chiamando questa funzione con 1 come parametro start dovrebbe fare il trucco.

+0

@ J.F.Sebastian: Che ho fatto io, signore. Grazie! –

+1

Usa xrange invece di range su Python 2.x – jfs

4

ho pensato che sarebbe stato interessante ed educativo per cercare di implementare un approccio leggermente più generale di quello che stai chiedendo. Qui misco gli indici nell'elenco originale (piuttosto che nell'elenco stesso), escludendo gli indici bloccati, e uso quell'elenco-indice per selezionare gli elementi selezionabili dall'elenco originale. Questa non è una soluzione specifica, ma implementata come un generatore in modo da poter scegliere pigramente elementi.

Sentitevi liberi di modificare, se si può migliorare.

import random 

def partial_shuf(input_list, fixed_indices): 
    """Given an input_list, yield elements from that list in random order 
    except where elements indices are in fixed_indices.""" 
    fixed_indices = sorted(set(i for i in fixed_indices if i < len(input_list))) 
    i = 0 
    for fixed in fixed_indices: 
     aslice = range(i, fixed) 
     i = 1 + fixed 
     random.shuffle(aslice) 
     for j in aslice: 
      yield input_list[j] 
     yield input_list[fixed] 
    aslice = range(i, len(input_list)) 
    random.shuffle(aslice) 
    for j in aslice: 
     yield input_list[j] 

print '\n'.join(' '.join((str(i), str(n))) for i, n in enumerate(partial_shuf(range(4, 36), [0, 4, 9, 17, 25, 40]))) 

assert sorted(partial_shuf(range(4, 36), [0, 4, 9, 17, 25, 40])) == range(4, 36) 
Problemi correlati