2012-07-29 18 views
5

¿Es posible mezclar solo una parte (continua) de una lista dada (o matriz en numpy)?Solucionar el primer elemento, mezclar el resto de una lista/matriz

Si esto no es posible en general, ¿qué ocurre con el caso especial en el que se fija el primer elemento mientras que el resto de la lista/matriz se debe barajar? Por ejemplo, tengo una lista/matriz:

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

donde el primer elemento siempre debe mantenerse, mientras que el resto van a ser barajado en varias ocasiones.

Una forma posible es barajar toda la lista primero, y luego verificar el primer elemento, si no es el elemento fijo especial (por ej. None), luego cambiar su posición por la del elemento especial (que luego requeriría una búsqueda).

¿Hay alguna forma mejor de hacerlo?

Respuesta

5

matrices numpy no copian los datos al corte:

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

Como elijo implementar usando una matriz numpy, esta es la mejor solución en mi caso.Otras soluciones también son muy útiles y esperamos que otras las encuentren adecuadas en sus respectivos casos de uso. – skyork

9

¿Por qué no

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

@DavidRobinson, gracias. ¿Lo anterior está en su lugar, lo que significa que no hay una nueva copia de una parte de la lista/matriz creada? – skyork

+2

@kojiro 'shuffled_lst' no existe antes de eso. Probablemente quiera decir: 'to_be_shuffled [1:] = rest' – jamylak

+2

@skyork no, tanto' shuffled_lst' como 'rest' son copias (parciales y completas) de los datos en' to_be_shuffled'. – kojiro

3

Tomé la función de reproducción aleatoria desde el módulo de biblioteca random estándar (que se encuentra en Lib\random.py) y modificado ligeramente para que se baraja sólo una parte de la lista especificada por start y stop. Hace esto en su lugar. ¡Disfrutar!

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] 

para sus propósitos, llamar a esta función con 1 como parámetro start debe hacer el truco.

+0

@ J.F.Sebastian: Eso lo hice señor. ¡Gracias! –

+1

Utilice xrange en lugar de rango en Python 2.x – jfs

4

Pensé que sería interesante y educativo intentar implementar un enfoque un poco más general que el que está pidiendo. Aquí mezclo los índices en la lista original (en lugar de la lista misma), excluyendo los índices bloqueados, y uso esa lista de índices para seleccionar elementos de la lista original. Esta no es una solución in situ, sino que se implementa como un generador para que pueda elegir elementos de forma perezosa.

No dude en corregirlo si puede mejorarlo.

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) 
Cuestiones relacionadas