2015-04-07 11 views
5

Czy istnieje sposób użycia operatora "splat" (np. a, *rest = somelist) w taki sposób, że zużywa on pewną liczbę elementów?Rozpakuj określoną liczbę elementów w Pythonie?

Przypadek użycia: chcę podzielić dane wejściowe na numer, listę list, inny numer i inną listę list.

Moje wejście wygląda następująco:

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 

I chcę nazwy first_num, first_arrangement, second_num, second_arrangement takie, że:

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

i tak dalej.

Aby to zrobić, dobrze byłoby móc spożywać określoną liczbę przedmiotów z pozycji iteracji. Coś takiego byłoby idealne jako etap pośredni: first_num, *[4]first_arrangement, second_num, *[4]second_arrangement = lines

Jaki jest normalny/kanoniczny/Pythoniczny sposób rozwiązania tego problemu?

+0

Którą wersję python używasz? – thefourtheye

+5

Nie możesz po prostu podzielić swoich argumentów => 'first_arrangement = args [1: 5]' ...? –

+0

W odpowiedzi na pierwsze pytanie, nie ma sposobu, aby to zrobić z '*' – MJeffryes

Odpowiedz

2

myślę kanoniczną, pythonic sposobem na to byłoby umieścić ciężar na generatorze, że jesteś iteracji skończona. Chciałbym zdefiniować funkcję generatora tak:

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

Powiedzmy, że masz swoje dane na liście tak:

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] 
] 

Następnie pisząc:

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

daje żądane wyjście :

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

Możesz również yi ELD liczba i rozmieszczenie w tym samym czasie, a użytkownik ma zrobić kilka dodatkowych rozpakowanie, co może być bardziej naturalne podejście:

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) 

Jak @JoranBeasley pisze w komentarzach, ta forma sprawia, że ​​jest łatwy w użyciu krotki rozpakowanie w pętli for, tak:

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

świetna odpowiedź ... Dodałbym 'dla num, arr w generate_arangements (dane)' –

+0

@JoranBeasley Dzięki! Dobra sugestia, przymocowałem to do końca mojej odpowiedzi. – jme

1

Nie jest jasne, jaki format otrzymujesz dane. Są to ciągi, dane w pliku itp. Załóżmy, że data jest obiektem StringIO z próbki wejściowej. Można użyć itertools.islice na iteracyjnej wyodrębnić elementy n, np:

>>> 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]] 
Powiązane problemy