2015-04-07 4 views
5

Esiste un modo per utilizzare l'operatore "splat" (ad esempio a, *rest = somelist) in modo tale da consumare un determinato numero di elementi?Scompattate un determinato numero di elementi in Python?

Caso di utilizzo: desidero suddividere un input in un numero, un elenco di elenchi, un altro numero e un altro elenco di elenchi.

mio ingresso si presenta così:

5 
1 2 3 4 
5 6 7 8 
9 10 11 12 
13 14 15 16 
5 
1 2 3 4 
5 6 7 8 
9 10 11 12 
13 14 15 16 

E voglio i nomi first_num, first_arrangement, second_num, second_arrangement tale che:

first_num == 5 
first_arrangement == [[1, 2, 3, 4], [5, 6, 7, 8], ...] 

e così via.

Per fare ciò, sarebbe utile essere in grado di consumare un determinato numero di elementi dall'iter iterabile che ho ottenuto cedendo le linee. Qualcosa di simile sarebbe ideale come una fase intermedia: first_num, *[4]first_arrangement, second_num, *[4]second_arrangement = lines

Qual è il modo normale/canonico/pititico per risolvere questo?

+0

Quale versione di python stai usando? – thefourtheye

+5

non puoi semplicemente tagliare i tuoi argomenti => 'first_arrangement = args [1: 5]' ...? –

+0

In risposta alla prima domanda, non c'è modo di farlo con '*' – MJeffryes

risposta

2

penso che il modo divinatorio canonica per farlo sarebbe quello di mettere l'onere sul generatore che si sta scorrendo sopra. Mi piacerebbe definire una funzione generatore in questo modo:

import itertools 

def generate_arrangements(iterable, size=4): 
    iterator = iter(iterable) 
    while True: 
     yield next(iterator) 
     yield list(list(row) for row in itertools.islice(iterator, size)) 

Diciamo che avete i vostri dati in un elenco in questo modo:

data = [ 
    5, 
    [1, 2, 3, 4], 
    [5, 6, 7, 8], 
    [9, 10, 11, 12], 
    [13, 14, 15, 16], 
    5, 
    [1, 2, 3, 4], 
    [5, 6, 7, 8], 
    [9, 10, 11, 12], 
    [13, 14, 15, 16] 
] 

Poi la scrittura:

first_num, first_arr, second_num, second_arr = generate_arrangements(data) 

ti dà l'output desiderato :

>>> first_num 
5 
>>> first_arr 
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] 

Si può anche y campo il numero e la disposizione allo stesso tempo, e hanno l'utente fare un po 'spacchettamento in più, che potrebbe essere un approccio più naturale:

import itertools 

def generate_arrangements(iterable): 
    iterator = iter(iterable) 
    while True: 
     number = next(iterator) 
     arrangement = list(list(row) for row in itertools.islice(iterator, 4)) 
     yield number, arrangement 

(first_num, first_arr), (second_num, second_arr) = generate_arrangements(data) 

Come scrive @JoranBeasley nei commenti, questa forma lo rende facile da usare tuple decompressione in un ciclo for, in questo modo:

for num,arr in generate_arrangements(data): 
    print(num) 
    print(arr) 
+0

ottima risposta ... vorrei aggiungere 'per num, arr in generate_arangements (dati)' –

+0

@JoranBeasley Grazie! Buon suggerimento, l'ho attaccato alla fine della mia risposta. – jme

1

Non è chiaro quale formato si ricevono i dati. Sono queste stringhe, i dati nel file, ecc. Supponiamo che data sia un oggetto StringIO dell'input di esempio. È possibile utilizzare itertools.islice su un iteratore per estrarre n elementi, per esempio:

>>> from itertools import islice 
>>> d = iter(data) 
>>> first_num = int(next(d)) 
>>> first_arrangement = [[int(x) for x in l.split()] for l in islice(d, 4)] 
>>> print(first_num, first_arrangement) 
5 [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] 
Problemi correlati