Padding ou tronquer une liste Python

j'aimerais tronquer ou tamponner une liste. Par exemple: pour la taille 4:

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

je peux voir un couple de façons:

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

Ou un court, mais de moins en moins efficace:

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

Est-il une façon plus élégante de le faire?

17
demandé sur thefourtheye 2015-05-27 10:13:58

7 réponses

trancher en utilisant un index plus grand que la longueur d'une liste retourne juste la liste entière.

la Multiplication d'une liste par une valeur négative retourne une liste vide.

cela signifie Que la fonction peut être écrite comme suit:

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]: []
19
répondu DTing 2015-05-27 07:34:22

Vous pouvez utiliser itertools module pour le rendre complètement paresseux, comme ceci

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

ici, nous enchaînons la séquence réelle avec le répéteur infini avec le filler valeur. Et puis on coupe l'itérateur enchaîné à size.

Donc, si la séquence a moins d'éléments que size,chain va commencer à consommer le repeat. Si la séquence a au moins size, puis chain n'aura même pas à utiliser le repeat.

le principal avantage de cette méthode est que, la liste complète tronquée ou capitonnée n'est pas créée en mémoire, à moins qu'elle ne soit demandée. Donc, si tout ce que vous allez faire est de le parcourir, il vous suffit de le parcourir comme ceci

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

Ou, si vous voulez l'utiliser avec un autre ou garnis collier de liste, vous pouvez toujours le faire sans créer une liste réelle, comme ceci

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

La Paresse Des Roches ;-)

22
répondu thefourtheye 2015-05-28 06:55:34

version en place:

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

version de la Copie:

l[:n] + [0] * (n - len(l))
6
répondu Vincent 2015-05-27 08:23:52

Vous pouvez utiliser 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
répondu Kasrâmvd 2015-05-27 07:39:14

je pense que votre version d'origine est non seulement très simple mais aussi la plus efficace, posté jusqu'à présent. J'ai stocké toutes les réponses données ici dans des fichiers séparés (dont chacun exposant une fonction "trimmer") et les ai ensuite testées pour les deux capitonnage ainsi que la troncature. Voici les résultats:

$ python --version
Python 2.7.6

Padding une liste de 100 éléments de 200 éléments:

$ 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

la Troncation d'une liste de 100 éléments à 50 éléments:

$ 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
4
répondu Frerich Raabe 2015-05-27 07:49:52

juste une solution insignifiante. 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]
1
répondu tilaprimera 2015-05-27 08:25:54

ajouter -

ajouter des zéros jusqu'à ce que votre liste atteigne la longueur dont vous avez besoin:

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]

ignorez le None s

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

couper

Utilisation de l'épissage:

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

In [20]: x[:4]
Out[20]: [1, 2, 3, 0]
1
répondu fixxxer 2015-05-28 06:15:06