2012-12-12 21 views
8

Załóżmy chcę pierwszego elementu, 3. poprzez elementy 200. rocznicy, a 201st elementu poprzez ostatni element po kroku rozmiarze 3, z listy w Pythonie.Python: krótsza składnia dla plasterków z przerwami?

Jednym ze sposobów na to jest z wyraźną indeksowania i konkatenacji:

new_list = old_list[0:1] + old_list[3:201] + old_list[201::3] 

Czy istnieje sposób, aby to zrobić za pomocą jednego indeksu na old_list? Chciałbym coś jak poniżej (wiem, że to nie składniowo od pracy indeksy lista nie może być list, a od Python niestety doesn't have slice literals; Po prostu szukam czegoś bliskiego):

new_list = old_list[[0, 3:201, 201::3]] 

mogę osiągnąć niektóre to poprzez przełączenie na tablice NumPy, ale bardziej interesuje mnie, jak to zrobić dla natywnych list Pythona. I może również tworzyć a slice maker czy coś takiego, a być może, że pod silną rękę dając mi równoważny przedmiot plaster do reprezentowania składu wszystkich moich pożądanych plasterki.

ale szukam czegoś, co nie wiąże się tworząc nową klasę zarządzania plastry. Chcę po prostu rodzaj złączyć składni plasterka i paszy, że na mojej liście i mieć listę rozumieją, że oznacza to, że aby dostać osobno plasterki i złączyć ich odpowiednich wyników w końcu.

+1

„Python niestety nie ma prymitywów slice” Nawet 'slice'? –

+0

Przepraszam, powinienem był mówić o literałach plastycznych, a nie o prymitywach. Oznacza to, że nie można po prostu przekazać składni '(0: 10: 2)' jakby to był obiekt, który zawsze reprezentował indeksy. Trzeba przejść przez nudną dodatkową warstwę tworzenia własnego obiektu plastra, który niszczy wszystkie niuanse składni plastra. Zobacz moje [pytanie, które jest również powiązane w powyższym] (http://stackoverflow.com/questions/13706258/passing-python-slice-syntax-around-to-functions). – ely

Odpowiedz

5

obiektu ekspres slice (np SliceMaker ze swojego inne pytanie, lub np.s_) może akceptować wiele wycinków oddzielonych przecinkami; są one odbierane jako tuple z slice s lub innych obiektów:

from numpy import s_ 
s_[0, 3:5, 6::3] 
Out[1]: (0, slice(3, 5, None), slice(6, None, 3)) 

NumPy używa tego do wielowymiarowych tablic, ale można go używać do plasterka konkatenacji:

def xslice(arr, slices): 
    if isinstance(slices, tuple): 
     return sum((arr[s] if isinstance(s, slice) else [arr[s]] for s in slices), []) 
    elif isinstance(slices, slice): 
     return arr[slices] 
    else: 
     return [arr[slices]] 
xslice(list(range(10)), s_[0, 3:5, 6::3]) 
Out[1]: [0, 3, 4, 6, 9] 
xslice(list(range(10)), s_[1]) 
Out[2]: [1] 
xslice(list(range(10)), s_[:]) 
Out[3]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
+0

Nie działa dla '' xslice (lista (zakres (10)), [1,2,3]) '', ani moja ostatnia wersja. Moja pierwsza wersja to robi. – Dzhuang

+0

@Dzhuang thanks! Poprawiono edycję, aby przetestować 'insinstance (..., slice)', zamieniając 2 ostatnie przypadki. – ecatmur

0

Jesteś prawdopodobnie lepiej pisać swój własny rodzaj sekwencji.

>>> L = range(20) 
>>> L 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 
>>> operator.itemgetter(*(range(1, 5) + range(10, 18, 3)))(L) 
(1, 2, 3, 4, 10, 13, 16) 

I możesz zacząć na tym:

>>> operator.itemgetter(*(range(*slice(1, 5).indices(len(L))) + range(*slice(10, 18, 3).indices(len(L)))))(L) 
(1, 2, 3, 4, 10, 13, 16) 
+0

Używałbym 'itertools.islice' i' itertools.chain' do ich konstruowania. – PaulMcG

0

Dlaczego don; t utworzyć niestandardowy segment dla celów

>>> from itertools import chain, islice 
>>> it = range(50) 
>>> def cslice(iterable, *selectors): 
    return chain(*(islice(iterable,*s) for s in selectors)) 

>>> list(cslice(it,(1,5),(10,15),(25,None,3))) 
[1, 2, 3, 4, 10, 11, 12, 13, 14, 25, 28, 31, 34, 37, 40, 43, 46, 49] 
+1

Czy spojrzałeś na link, który znalazłem powyżej, na poprzednie pytanie, które zadałem?Odpowiedź na to pytanie w mniejszym lub większym stopniu odzwierciedla to samo, co twoja odpowiedź, ale ma lepszą składnię i nie wymaga 'itertools'. Moim głównym celem jest przekazanie dokładnie takiej składni plasterka, jaka jest. Dodawanie narzutów składniowych reprezentujących plasterki jako krotki i przekazywanie ich do nowego obiektu jest jeszcze gorsze niż łączenie oddzielnych plasterków. – ely

+0

@EMS: nie, ta odpowiedź opisuje sposób, w jaki można łatwo tworzyć plasterki, ale nie można ich używać, ponieważ indeksują elementy na liście. Rozwiązanie Abhijit robi to, co chcesz i możesz połączyć je z inną odpowiedzią, by mieć ładną składnię: 'cslice (it, make_slice [1: 5], make_slice [10:15], make_slice [25 :: 3]) ' – Bakuriu

+0

@Bakuriu: to była moja cała uwaga. 'cslice' nie robi niczego poza łańcuchami plasterków, co jest gorsze od konkatenacji list. W odpowiedzi 'tuple's są używane jako argumenty do' cslice'. Dziękuję za pokazanie mi, że wyniki przykładu 'SliceMaker' również mogą zostać przekazane. To zmniejsza część składni tej odpowiedzi, ale niewystarczająco. – ely

0

Nie jestem pewien, czy to jest „lepszy ”, ale działa, więc dlaczego nie ...

[y for x in [old_list[slice(*a)] for a in ((0,1),(3,201),(201,None,3))] for y in x]

to chyba powoli (szczególnie w porównaniu do cha w), ale jest to podstawowe Pythona (3.5.2 używane do testowania)