Reputation: 3294
I'd like to truncate or pad a list. E.g. for size 4:
[1,2,3] -> [1,2,3,0]
[1,2,3,4,5] -> [1,2,3,4]
I can see a couple of ways:
def trp(l, n):
""" Truncate or pad a list """
r = l[:n]
if len(r) < n:
r.extend([0] * (n - len(r)))
return r
Or a shorter, but less efficient:
map(lambda x, y: x if x else 0, m[0:n], [0] * n)
Is there a more elegant way of doing this?
Upvotes: 18
Views: 5562
Reputation: 239683
You can use itertools
module to make it completely lazy, like this
>>> 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]
Here, we chain the actual sequence with the infinite repeater with the filler
value. And then we slice the chained iterator to size
.
So, when if the sequence has lesser number of elements than size
, chain
will start consuming the repeat
. If the sequence has at least size
elements, then chain
will not even have to use the repeat
.
The main advantage of this method is that, the complete trimmed or padded list is not created in memory, unless asked for it. So, if all you are going to do is to iterate it, then you can simply iterate it like this
>>> for item in trimmer([1, 2, 3, 4, 5], 4):
... print(item * 2)
...
...
2
4
6
8
Or, if you want to use it with another trimmed or padded list, then you can still do that without creating an actual list, like this
>>> 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
Laziness Rocks ;-)
Upvotes: 24
Reputation: 16164
Append zeroes till your list reaches the length you need:
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]
Ignore the None
s
In [33]: x
Out[33]: [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]
Use splicing:
In [19]: x
Out[19]: [1, 2, 3, 0, 1, 2, 3, 4]
In [20]: x[:4]
Out[20]: [1, 2, 3, 0]
Upvotes: 1
Reputation: 882
Just a trivial solution. 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]
Upvotes: 1
Reputation: 13423
In-place version:
l[n:] = [0] * (n - len(l))
Copy version:
l[:n] + [0] * (n - len(l))
Upvotes: 7
Reputation: 94549
I think your original version is not only very straightforward but also the most efficient one posted so far. I stored all answers given here in separate files (each of which exposing a 'trimmer' function) and then tested them for both padding as well as truncating. Here are the results:
$ python --version
Python 2.7.6
Padding a list of 100 elements to 200 elements:
$ 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
Truncating a list of 100 elements to 50 elements:
$ 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
Upvotes: 4
Reputation: 107347
You can use 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]
Upvotes: 4
Reputation: 39307
Slicing using an index greater than the length of a list just returns the entire list.
Multiplying a list by a negative value returns an empty list.
That means the function can be written as:
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]: []
Upvotes: 21