Alcuni integrati per riempire un elenco in Python


110

Ho un elenco di dimensioni < N e voglio aggiungerlo alla taglia N con un valore.

Certamente, posso usare qualcosa di simile a quanto segue, ma sento che dovrebbe esserci qualcosa che mi è sfuggito:

>>> N = 5
>>> a = [1]
>>> map(lambda x, y: y if x is None else x, a, ['']*N)
[1, '', '', '', '']

Perchè vuoi fare questo? Probabilmente c'è un modo migliore.
Katriel

Serializzo l'elenco in una stringa separata da tabulazioni con il numero fisso di colonne.
newtover

Intendi dire che stai facendo qualcosa come '\ t'.join ([1,' ',' ',' ',' '])? Forse puoi dirci di più su ciò che intendi realizzare, quindi possiamo provare a farci un'idea.
satoru

@ Satoru.Logic: sì, stampa >> a_stream, '\ t'.join (the_list) è tutto ciò che voglio implementare
novità

Risposte:


165
a += [''] * (N - len(a))

o se non vuoi cambiare aposto

new_a = a + [''] * (N - len(a))

puoi sempre creare una sottoclasse di list e chiamare il metodo come preferisci

class MyList(list):
    def ljust(self, n, fillvalue=''):
        return self + [fillvalue] * (n - len(self))

a = MyList(['1'])
b = a.ljust(5, '')

3
Questo sembra molto meglio, ma mi aspetto qualcosa di simile a un riempimento o pad metodo o una funzione =)
newtover

30

Penso che questo approccio sia più visivo e pitonico.

a = (a + N * [''])[:N]

Mi ci vuole mezzo minuto per capire. La risposta accettata è molto più semplice.
Richard Möhn

3
@ RichardMöhn "pitonico" significa "idiomatico". Più a lungo usi Python, più naturale troverai questa sintassi.
Nuno André

4
So cosa significa "pitonico". E uso Python ininterrottamente dal 2014. Ancora non trovo naturale la tua risposta.
Richard Möhn

Cosa rende pitonico costruire un elenco intermedio usa e getta?
DylanYoung

1
@ DylanYoung questo non è il caso per il primo quando N < len(a). È il caso della seconda risposta che hai fornito.
kon psych

25

Non esiste una funzione incorporata per questo. Ma potresti comporre gli integrati per il tuo compito (o qualsiasi altra cosa: p).

(Modificato da itertool padnonee takericette)

from itertools import chain, repeat, islice

def pad_infinite(iterable, padding=None):
   return chain(iterable, repeat(padding))

def pad(iterable, size, padding=None):
   return islice(pad_infinite(iterable, padding), size)

Uso:

>>> list(pad([1,2,3], 7, ''))
[1, 2, 3, '', '', '', '']

6

La risposta di gnibbler è più carina, ma se hai bisogno di un builtin, potresti usare itertools.izip_longest( zip_longestin Py3k):

itertools.izip_longest( xrange( N ), list )

che restituirà un elenco di tuple ( i, list[ i ] )compilate a Nessuno. Se devi sbarazzarti del contatore, fai qualcosa come:

map( itertools.itemgetter( 1 ), itertools.izip_longest( xrange( N ), list ) )

1
Sapevo di izip_longest ma il codice risultante non sembra carino =)
newtover

2
Credo che tu intenda operator.itemgetter(). Anche i Nonevalori dovevano essere sostituiti con "".
pylang

5

Puoi anche usare un semplice generatore senza build in. Ma non riempirei l'elenco, ma lascerei che la logica dell'applicazione gestisca un elenco vuoto.

Ad ogni modo, iteratore senza buildins

def pad(iterable, padding='.', length=7):
    '''
    >>> iterable = [1,2,3]
    >>> list(pad(iterable))
    [1, 2, 3, '.', '.', '.', '.']
    '''
    for count, i in enumerate(iterable):
        yield i
    while count < length - 1:
        count += 1
        yield padding

if __name__ == '__main__':
    import doctest
    doctest.testmod()

4

Se vuoi riempire con Nessuno invece di '', map () fa il lavoro:

>>> map(None,[1,2,3],xrange(7))

[(1, 0), (2, 1), (3, 2), (None, 3), (None, 4), (None, 5), (None, 6)]

>>> zip(*map(None,[1,2,3],xrange(7)))[0]

(1, 2, 3, None, None, None, None)

2
Per dire francamente, a + [''] * (N-len (a)) sembra molto più chiaro. Inoltre, manca il casting per l'elenco. Ma grazie comunque.
newtover

4

more-itertoolsè una libreria che include uno paddedstrumento speciale per questo tipo di problema:

import more_itertools as mit

list(mit.padded(a, "", N))
# [1, '', '', '', '']

In alternativa, more_itertoolsimplementa anche le ricette di itertools Python incluse padnonee takecome menzionato da @kennytm, quindi non devono essere reimplementate:

list(mit.take(N, mit.padnone(a)))
# [1, None, None, None, None]

Se desideri sostituire il Noneriempimento predefinito , utilizza una comprensione dell'elenco:

["" if i is None else i for i in mit.take(N, mit.padnone(a))]
# [1, '', '', '', '']

2

Per uscire da kennytm:

def pad(l, size, padding):
    return l + [padding] * abs((len(l)-size))

>>> l = [1,2,3]
>>> pad(l, 7, 0)
[1, 2, 3, 0, 0, 0, 0]


1
extra_length = desired_length - len(l)
l.extend(value for _ in range(extra_length))

Ciò evita qualsiasi allocazione aggiuntiva, a differenza di qualsiasi soluzione che dipende dalla creazione e dall'aggiunta dell'elenco [value] * extra_length. Il metodo "extent" chiama prima __length_hint__l'iteratore, ed estende l'allocazione ldi molto prima di riempirlo dall'iteratore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.