填充或截断Python列表

时间:2015-05-27 07:13:58

标签: python list python-2.7

我想截断或填充列表。例如。尺寸4:

[1,2,3] -> [1,2,3,0]
[1,2,3,4,5] -> [1,2,3,4]

我可以看到几种方式:

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

或更短但效率更低:

map(lambda x, y: x if x else 0, m[0:n], [0] * n)

有更优雅的方式吗?

7 个答案:

答案 0 :(得分:22)

您可以使用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]

在这里,我们将实际序列与具有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

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

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

懒惰岩石; - )

答案 1 :(得分:19)

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

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

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

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]
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]: []

答案 2 :(得分:6)

就地版:

l[n:] = [0] * (n - len(l))

复制版本:

l[:n] + [0] * (n - len(l))

答案 3 :(得分:4)

您可以使用numpy.pad

>>> def trp(a,n):
...    diff=n-len(a)
...    if diff >0:
...         return np.lib.pad(l2,(0,diff),'constant', constant_values=(0))
...    else :
...         return a[:n]
... 

>>> l1=[1, 2, 3, 4, 5]
>>> l2=[1, 2, 3]
>>> trp(l2,4)
array([1, 2, 3, 0])
>>> trp(l1,4)
[1, 2, 3, 4]

答案 4 :(得分:4)

我认为您的原始版本不仅非常简单,而且是迄今为止发布的最有效版本。我将这里给出的所有答案存储在单独的文件中(每个文件都展示了一个&#39; trimmer&#39;函数),然后测试它们的填充和截断。结果如下:

$ python --version
Python 2.7.6

将100个元素的列表填充到200个元素:

$ for VERSION in dmtri1 dmtri2 thefourtheye dting; do echo -n "$VERSION: "; python -m timeit -s "from $VERSION import trimmer; l = range(100)" -- 'list(trimmer(l, 200))'; done
dmtri1: 100000 loops, best of 3: 2.9 usec per loop
dmtri2: 10000 loops, best of 3: 27.1 usec per loop
thefourtheye: 100000 loops, best of 3: 5.78 usec per loop
dting: 100000 loops, best of 3: 2.69 usec per loop

将100个元素的列表截断为50个元素:

$ for VERSION in dmtri1 dmtri2 thefourtheye dting; do echo -n "$VERSION: "; python -m timeit -s "from $VERSION import trimmer; l = range(100)" -- 'list(trimmer(l, 50))'; done
dmtri1: 1000000 loops, best of 3: 0.832 usec per loop
dmtri2: 100000 loops, best of 3: 8.27 usec per loop
thefourtheye: 100000 loops, best of 3: 2.62 usec per loop
dting: 1000000 loops, best of 3: 1.29 usec per loop

答案 5 :(得分:1)

追加 -

附加零,直到列表达到您需要的长度:

In [31]: x
Out[31]: [1, 2, 3, 0]

In [32]: [x.append(0) for i in range(10 - len(x))]
Out[32]: [None, None, None, None, None, None]

忽略None s

In [33]: x
Out[33]: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]

截断

使用拼接:

In [19]: x
Out[19]: [1, 2, 3, 0, 1, 2, 3, 4]

In [20]: x[:4]
Out[20]: [1, 2, 3, 0]

答案 6 :(得分:1)

只是一个简单的解决方案。的 Unpythonic。

def f(a):
    length_a = len(a)
    limit = 4
    if length_a > limit:
      a = a[:limit]
    else:
      for i in xrange(0,limit - length_a):
        a.append(0)
    return a

>>> a = [1,2,3,4,5,6,7,7,8,8]
>>> b = [1]
>>> c = [1,2]
>>> f(a)
[1, 2, 3, 4]
>>> f(b)
[1, 0, 0, 0]
>>> f(c)
[1, 2, 0, 0]