填充或截断Python列表

dmi*_*tri 17 python list python-2.7

我想截断或填充列表.例如,大小为4:

[1,2,3] -> [1,2,3,0]
[1,2,3,4,5] -> [1,2,3,4]
Run Code Online (Sandbox Code Playgroud)

我可以看到几种方式:

def trp(l, n):
    """ Truncate or pad a list """
    r = l[:n]
    if len(r) < n:
        r.extend([0] * (n - len(r)))
    return r
Run Code Online (Sandbox Code Playgroud)

或者更短但效率更低:

map(lambda x, y: x if x else 0, m[0:n], [0] * n)
Run Code Online (Sandbox Code Playgroud)

有更优雅的方式吗?

the*_*eye 23

你可以使用itertools模块使它完全懒惰,就像这样

>>> from itertools import repeat, chain, islice
>>> def trimmer(seq, size, filler=0):
...     return islice(chain(seq, repeat(filler)), size)
... 
>>> list(trimmer([1, 2, 3], 4))
[1, 2, 3, 0]
>>> list(trimmer([1, 2, 3, 4, 5], 4))
[1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)

在这里,我们用无限转发器将实际序列与filler值链接起来.然后我们将链式迭代器切片为size.

因此,如果序列的元素数量少于size,chain则会开始消耗repeat.如果序列至少有size元素,那么chain甚至不必使用repeat.

此方法的主要优点是,除非要求,否则不会在内存中创建完整的修剪或填充列表.所以,如果您要做的就是迭代它,那么您可以像这样简单地迭代它

>>> for item in trimmer([1, 2, 3, 4, 5], 4):
...     print(item * 2)
...     
... 
2
4
6
8
Run Code Online (Sandbox Code Playgroud)

或者,如果您想将其与另一个修剪或填充列表一起使用,那么您仍然可以在不创建实际列表的情况下执行此操作,例如

>>> for item in chain(trimmer([1, 2, 3], 4), trimmer([1, 2, 3, 4, 5], 4)):
...     print(item, item * 2)
...     
... 
1 2
2 4
3 6
0 0
1 2
2 4
3 6
4 8
Run Code Online (Sandbox Code Playgroud)

懒惰岩石;-)


DTi*_*ing 20

使用大于列表长度的索引进行切片只会返回整个列表.

将列表乘以负值会返回一个空列表.

这意味着该函数可以写成:

def trp(l, n):
    return l[:n] + [0]*(n-len(l))

trp([], 4)
[0, 0, 0, 0]

trp([1,2,3,4], 4)
[1, 2, 3, 4]

trp([1,2,3,4,5], 4)
[1, 2, 3, 4]

trp([1,2,3], 4)
[1, 2, 3, 0]
Run Code Online (Sandbox Code Playgroud)
In [1]: a = [1,2,3]

In [2]: a[:4]
Out[2]: [1, 2, 3]

In [3]: [0]*0
Out[3]: []

In [4]: [0]*-1
Out[4]: []
Run Code Online (Sandbox Code Playgroud)


Vin*_*ent 6

就地版本:

l[n:] = [0] * (n - len(l))
Run Code Online (Sandbox Code Playgroud)

复制版本:

l[:n] + [0] * (n - len(l))
Run Code Online (Sandbox Code Playgroud)