2012-12-12 13 views
8

Supponiamo di volere il primo elemento, dal 3 ° al 200 ° elemento, e l'elemento 201st attraverso l'ultimo elemento del gradino 3, da un elenco in Python.Python: sintassi più breve per sezioni con spazi vuoti?

un modo per farlo è con l'indicizzazione distinto e la concatenazione:

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

C'è un modo per fare questo con un solo indice su old_list? Mi piacerebbe qualcosa di simile alla seguente (so che questo non funziona sintatticamente in quanto indici delle liste non possono essere liste e dal momento che Python purtroppo doesn't have slice literals, io sono solo in cerca di qualcosa di simile):

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

posso raggiungere alcuni dei questo passando agli array NumPy, ma sono più interessato a come farlo per gli elenchi Python nativi. Potrei anche creare a slice maker o qualcosa di simile, e possibilmente armare forte nel darmi un equivalente oggetto fetta per rappresentare la composizione di tutte le mie fette desiderate.

Ma sto cercando qualcosa che non implichi la creazione di una nuova classe per gestire le fette. Voglio solo concatenare la sintassi della slice e inserirla nella mia lista e far capire alla lista che significa ottenere separatamente le slice e concatenare i loro rispettivi risultati alla fine.

+1

"Python sfortunatamente non ha primitive di slice" Neanche 'slice'? –

+0

Scusate, avrei dovuto dire letterali di sezione, non affettare le primitive. Cioè, non puoi semplicemente aggirare la sintassi '(0: 10: 2)' come se fosse esso stesso un oggetto che rappresentava sempre degli indici. Devi passare attraverso il noioso ulteriore livello di creazione del tuo oggetto fetta, che distrugge tutte le sottigliezze della sintassi della sezione. Vedi la mia [domanda che è anche collegata in precedenza] (http://stackoverflow.com/questions/13706258/passing-python-slice-syntax-around-to-functions). – ely

risposta

5

un oggetto fetta macchinetta (ad es SliceMaker dal altra domanda, o np.s_) può accettare più sezioni separate da virgola; vengono ricevuti come tuple di slice s o altri oggetti:

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

NumPy utilizza questo per gli array multidimensionali, ma è possibile utilizzarlo per la fetta di concatenazione:

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

Non funziona con '' xslice (list (range (10)), [1,2,3]) '', né la mia ultima revisione. La mia prima revisione lo fa. – Dzhuang

+0

@Dzhuang grazie! Migliorata la tua modifica per testare 'insinstance (..., slice)', scambiando gli ultimi 2 casi. – ecatmur

0

probabilmente stai meglio scrivere il proprio tipo di sequenza.

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

E per iniziare su quel:

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

Io userei 'itertools.islice' e' itertools.chain' per costruirli. – PaulMcG

0

Perché don; t si crea una fetta personalizzato per il vostro scopo

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

Hai guardato il link che ho inserito sopra a una domanda precedente che ho chiesto?La risposta a questa domanda rappresenta più o meno la stessa cosa della tua risposta, ma ha una sintassi migliore e non ha bisogno di 'itertools'. L'obiettivo principale del mio è quello di passare direttamente esattamente la sintassi della slice così com'è. Aggiungere l'overhead sintattico di rappresentare le sezioni come tuple e passarle a un nuovo oggetto è anche peggio che concatenare sezioni separate. – ely

+0

@EMS: no, quella risposta descrive semplicemente un modo per creare sezioni facilmente, ma non possono essere utilizzate così come sono per indicizzare gli elementi in una lista. La soluzione Abhijit fa quello che vuoi, e puoi combinarlo con l'altra risposta per avere una bella sintassi come: 'cslice (it, make_slice [1: 5], make_slice [10:15], make_slice [25 :: 3]) ' – Bakuriu

+0

@Bakuriu: questo era il mio punto. 'cslice' non fa altro che incatenare le fette, che è inferiore alla concatenazione di liste. Nella risposta, 'tuple's sono usati come argomenti per' cslice'. Grazie per avermi mostrato che è possibile inoltrare anche i risultati dell'esempio 'SliceMaker'. Questo allevia alcuni dei rigonfiamenti della sintassi di questa risposta, ma non abbastanza. – ely

0

Non sono sicuro se questo è "meglio ", ma funziona così perché non ...

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

E 'probabilmente lento (soprattutto rispetto al cha in) ma è python di base (3.5.2 usato per i test)

Problemi correlati