Python中一些内置的方法用于填充列表

170

我有一个大小小于N的列表,我想用一个值填充它到大小N。

当然,我可以使用类似以下的方法,但我感觉应该有我错过的东西:

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

你为什么想这样做?可能有更好的方法。 - Katriel
我将列表序列化为具有固定列数的制表符分隔字符串。 - newtover
你的意思是你正在做类似于'\t'.join([1,'','','',''])的事情吗?也许你可以告诉我们更多关于你打算实现什么,然后我们可以尝试提出一些想法。 - satoru
@Satoru.Logic:是的,我想要实现的就是_print >> a_stream, '\t'.join(the_list)_。 - newtover
14个回答

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

或者如果你不想直接修改a

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

你可以随时创建一个list的子类,并将方法命名为任何你想要的名称。

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

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

49

我认为这种方法更加直观且符合Python风格。

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

7
我需要半分钟才能理解这个。被接受的答案更加简单明了。 - Richard Möhn
7
"pythonic" 意味着 "符合 Python 语言特性的"。你使用 Python 的时间越长,就会越自然地使用这种语法。 - Nuno André
20
我知道“pythonic”的含义,并且自2014年以来一直在持续使用Python。然而,我仍然觉得你的回答不太自然。 - Richard Möhn
4
构建一个临时的可抛弃列表是什么让它成为Pythonic的? - DylanYoung
3
与被采纳的答案不同,此答案强制长度为“N”,这可能是可取的。这取决于应用程序,这就是此答案有用的原因。 - kon psych
显示剩余6条评论

33

这方面没有内置函数可用。但是你可以组合已有的函数来完成你的任务(或者任何任务 :p)。

(修改自itertool中的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, '', '', '', '']

不错的方法:chain(iterable, repeat(padding)) - RoyM

14

more-itertools 是一个库,其中包含一个专门用于此类问题的特殊工具padded

import more_itertools as mit

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

或者,more_itertools 还实现了 Python 的 itertools recipes,包括 padnonetake,正如 @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, '', '', '', '']

mit.take(N, mit.padnone(a)) 本身返回一个列表。 - PlaceReporter99

8

gnibbler的答案更好,但如果你需要一个内置的函数,你可以使用itertools.izip_longest(在Py3k中为zip_longest):

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
如果您想使用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

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

5

使用迭代器并利用next的默认参数:

i = iter(a)
a = [next(i, '') for _ in range(N)]

简要解释:

我们希望生产N个项目。因此使用for _ in range(N)。然后元素应该尽可能多地来自a,其余的是''。使用a上的迭代器,我们获取所有可能的元素,当我们得到StopIteration时,将返回默认值,即''


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

这样做可以避免额外分配内存,与任何依赖于创建和附加列表 [value] * extra_length 的解决方案不同。 "extend" 方法首先在迭代器上调用 __length_hint__,然后扩展 l 的分配大小,并从迭代器中填充它。


更简洁地说,a.extend((N-len(a))*[padding_value])(我使用OP符号)。 - mmj
您的提案涉及分配一个列表,然后使用“extend”来追加它。我的方法避免了额外的分配;不会创建新的列表,只有一个生成器对象。 - Paul Crowley

4

您可以使用*可迭代解包操作符

N = 5
a = [1]

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

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

输出:

[1, '', '', '', '']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接