Alguns integrados para preencher uma lista em python

110

Eu tenho uma lista de tamanho < N e quero preenchê-la até o tamanho N com um valor.

Certamente, posso usar algo como o seguinte, mas sinto que deve haver algo que perdi:

>>> N = 5
>>> a = [1]
>>> map(lambda x, y: y if x is None else x, a, ['']*N)
[1, '', '', '', '']
newtover
fonte
Por que você quer fazer isso? Provavelmente existe uma maneira melhor.
Katriel
Eu serializo a lista em uma string separada por tabulação com o número fixo de colunas.
newtover
Você quer dizer que está fazendo algo como '\ t'.join ([1,' ',' ',' ',' '])? Talvez você possa nos contar mais sobre o que pretende implementar, então podemos tentar ter uma ideia.
satoru
@ Satoru.Logic: sim, imprimir >> a_stream, '\ t'.join (the_list) é tudo que eu quero implementar
newtover

Respostas:

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

ou se você não quiser mudar ade lugar

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

você sempre pode criar uma subclasse de lista e chamar o método como quiser

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

a = MyList(['1'])
b = a.ljust(5, '')
John La Rooy
fonte
3
Isso parece muito melhor, mas eu ainda esperam algo como um preenchimento ou pad método ou função =)
newtover
30

Eu acho que essa abordagem é mais visual e pitônica.

a = (a + N * [''])[:N]
Nuno André
fonte
Isso me leva meio minuto para entender. A resposta aceita é muito mais direta.
Richard Möhn
3
@ RichardMöhn "pythônico" significa "idiomático". Quanto mais você usar o Python, mais natural achará essa sintaxe.
Nuno André
4
Eu sei o que 'pythônico' significa. E tenho usado Python continuamente desde 2014. Ainda não acho sua resposta natural.
Richard Möhn
O que torna pítônico construir uma lista intermediária descartável?
DylanYoung
1
@DylanYoung, este não é o caso para o primeiro quando N < len(a). É o caso da segunda resposta que você forneceu.
kon psych
25

Não há função embutida para isso. Mas você pode compor os recursos internos para sua tarefa (ou qualquer coisa: p).

(Modificado de itertool padnonee takereceitas)

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, '', '', '', '']
Kennytm
fonte
6

A resposta do gnibbler é mais agradável, mas se você precisar de um integrado, pode usar itertools.izip_longest( zip_longestno Py3k):

itertools.izip_longest( xrange( N ), list )

que retornará uma lista de tuplas ( i, list[ i ] )preenchidas como Nenhum. Se você precisar se livrar do contador, faça algo como:

map( itertools.itemgetter( 1 ), itertools.izip_longest( xrange( N ), list ) )
Katriel
fonte
1
Eu sabia sobre izip_longest, mas o código resultante não parece bom =)
newtover
2
Eu acredito que você quer dizer operator.itemgetter(). Além disso, os Nonevalores precisavam ser substituídos "".
pylang de
5

Você também pode usar um gerador simples sem nenhum build ins. Mas eu não preencheria a lista, mas deixaria a lógica do aplicativo lidar com uma lista vazia.

De qualquer forma, iterador sem 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()
Thierry
fonte
4

Se você deseja preencher com Nenhum em vez de '', map () faz o trabalho:

>>> 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)
Federico
fonte
2
Para dizer francamente, a + [''] * (N-len (a)) parece muito mais claro. Além disso, falta elenco para listar. Mas obrigado mesmo assim.
newtover
4

more-itertoolsé uma biblioteca que inclui uma paddedferramenta especial para este tipo de problema:

import more_itertools as mit

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

Como alternativa, more_itertoolstambém implementa receitas de itertools Python, incluindo padnonee takeconforme mencionado por @kennytm, para que não precisem ser reimplementadas:

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

Se você deseja substituir o Nonepreenchimento padrão , use uma compreensão de lista:

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

Para sair do 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]
aberger
fonte
2

você pode usar o * operador de desempacotamento iterável :

N = 5
a = [1]

pad_value = ''
pad_size = N - len(a)

final_list = [*a, *[pad_value] * pad_size]
print(final_list)

resultado:

[1, '', '', '', '']
Kederrac
fonte
1
extra_length = desired_length - len(l)
l.extend(value for _ in range(extra_length))

Isso evita qualquer alocação extra, ao contrário de qualquer solução que dependa da criação e do acréscimo da lista [value] * extra_length. O método "extend" primeiro chama __length_hint__o iterador e estende a alocação lpor muito antes de preenchê-la a partir do iterador.

Paul Crowley
fonte