Некоторые встроены в список на Python

110

У меня есть список размером < N, и я хочу дополнить его значением до размера N.

Конечно, я могу использовать что-то вроде следующего, но я чувствую, что должно быть что-то, что я пропустил:

>>> N = 5
>>> a = [1]
>>> map(lambda x, y: y if x is None else x, a, ['']*N)
[1, '', '', '', '']
новый
источник
почему ты хочешь сделать это? Наверное, есть способ получше.
Катриэль
Я сериализую список в строку, разделенную табуляцией, с фиксированным количеством столбцов.
newtover
Вы имеете в виду, что делаете что-то вроде '\ t'.join ([1,' ',' ',' ',' '])? Может быть, вы расскажете нам больше о том, что вы собираетесь реализовать, тогда мы попробуем придумать идею.
satoru
@ Satoru.Logic: да, print >> a_stream, '\ t'.join (the_list) - это все, что я хочу реализовать
newtover

Ответы:

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

или если вы не хотите менять aместо

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

вы всегда можете создать подкласс списка и вызвать метод как угодно

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

a = MyList(['1'])
b = a.ljust(5, '')
Джон Ла Рой
источник
3
Это выглядит намного лучше, но я все еще ожидаю чего-то вроде метода или функции fill или pad =)
newtover
31

Я думаю, что этот подход более наглядный и питонический.

a = (a + N * [''])[:N]
Нуно Андре
источник
На это у меня уходит полминуты. Принятый ответ намного проще.
Ричард Мён
4
@ RichardMöhn «питонический» означает «идиоматический». Чем дольше вы используете Python, тем более естественным будет этот синтаксис.
Нуно Андре
4
Я знаю, что означает «питонический». И я постоянно использую Python с 2014 года. Я все еще не считаю ваш ответ естественным.
Ричард Мён
Что побуждает создавать промежуточный список выбрасываемых отходов?
DylanYoung,
1
@DylanYoung это не первый случай N < len(a). Это случай второго предоставленного вами ответа.
kon psycho
25

Для этого нет встроенной функции. Но вы можете составить встроенные программы для своей задачи (или чего угодно: p).

(Изменено из itertool's padnoneи takeрецептов)

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)

Использование:

>>> list(pad([1,2,3], 7, ''))
[1, 2, 3, '', '', '', '']
Kennytm
источник
6

Ответ gnibbler лучше, но если вам нужна встроенная функция , вы можете использовать itertools.izip_longest( zip_longestв Py3k):

itertools.izip_longest( xrange( N ), list )

который вернет список кортежей, ( i, list[ i ] )заполненный значением None. Если вам нужно избавиться от счетчика, сделайте что-нибудь вроде:

map( itertools.itemgetter( 1 ), itertools.izip_longest( xrange( N ), list ) )
Катриэль
источник
1
Я знал про izip_longest, но в результате код выглядит не очень красиво =)
newtover
2
Я верю, вы имеете в виду operator.itemgetter(). Также Noneзначения необходимо было заменить на "".
pylang
5

Вы также можете использовать простой генератор без каких-либо сборок. Но я бы не стал дополнять список, а позволил логике приложения работать с пустым списком.

Так или иначе, итератор без сборок

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

Если вы хотите использовать None вместо '', map () выполнит эту работу:

>>> 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
Откровенно говоря, a + [''] * (N-len (a)) выглядит намного яснее. Кроме того, отсутствует приведение к списку. Но все равно спасибо.
newtover 06
4

more-itertools- это библиотека, которая включает специальный paddedинструмент для решения такого рода проблем:

import more_itertools as mit

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

В качестве альтернативы more_itertoolsтакже реализует рецепты Python itertools, включая padnoneи takeкак указано @kennytm, поэтому их не нужно повторно реализовывать:

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

Если вы хотите заменить Noneотступ по умолчанию , используйте понимание списка:

["" if i is None else i for i in mit.take(N, mit.padnone(a))]
# [1, '', '', '', '']
пиланг
источник
2

Чтобы выйти из 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))

Это позволяет избежать какого-либо дополнительного выделения, в отличие от любого решения, которое зависит от создания и добавления списка [value] * extra_length. Метод «extend» сначала вызывает __length_hint__итератор и на lстолько же увеличивает выделение , прежде чем заполнить его из итератора.

Пол Кроули
источник