Clipping a list with a dynamic index in [: index]

I need to slice a list using negative dynamic indexes ([: -index]). This was easy until I realized that if my dynamic index value was 0, no items were returned, not the whole list. How can I implement this so that when the index is 0, it returns the whole row? My code is very long and complex, but basically this example shows the problem:

arr='test text' index=2 print arr[:-index] >>'test te' #Entire string minus 2 from the right index=1 print arr[:-index] >>'test tex' #Entire string minus 1 from the right index=0 print arr[:-index] >>'' #I would like entire string minus 0 from the right 

Note. I am using Python 2.7.

+5
source share
4 answers

Another potential solution for fun.

 >>> arr = [1, 2, 3] >>> index = 0 >>> arr[:-index or None] [1, 2, 3] >>> index = 1 >>> arr[:-index or None] [1, 2] 

For better performance in immutable sequence types such as strings, you can avoid slicing the sequence completely if the index is 0 by checking the index value before the slice operation.

Here are three functions for testing in terms of performance:

 def shashank1(seq, index): return seq[:-index or None] def shashank2(seq, index): return index and seq[:-index] or seq def shashank3(seq, index): return seq[:-index] if index else seq 

The last two should be much faster when the index is 0, but may be slower (or faster) in other cases.


Updated test code: http://repl.it/oA5

Note. The results depend on the implementation of Python.

+7
source

This distracts from the purity of the slice notation, but you can do

 >>> arr[: len(arr) - 2] 'test te' >>> arr[: len(arr) - 1] 'test tex' >>> arr[: len(arr) - 0] 'test text' 
+6
source

You can use None rather than 0 to get the full snippet:

 >>> arr = [1, 2, 3] >>> index = 1 >>> arr[:-index if index else None] [1, 2] >>> index = 0 >>> arr[:-index if index else None] [1, 2, 3] 

My testing:

 import timeit def jonrsharpe(seq, index): return seq[:-index if index else None] def Cyber(seq, index): return seq[:len(arr) - index] def shashank(seq, index): return seq[:-index or None] if __name__ == '__main__': funcs = ('jonrsharpe', 'Cyber', 'shashank') arr = range(1000) setup = 'from __main__ import arr, {}'.format(', '.join(funcs)) for func in funcs: print func for x in (0, 10, 100, 1000): print x, print timeit.timeit('{}(arr, {})'.format(func, x), setup=setup) 

and results:

 jonrsharpe 0 2.9769377505 10 3.10071766781 100 2.83629358793 1000 0.252808797871 Cyber 0 3.11828875501 10 3.10177615276 100 2.82515282642 1000 0.283648679403 shashank 0 2.99515364824 10 3.11204965989 100 2.85491723351 1000 0.201558213116 
+4
source

Since I would not be able to sleep until I chose the best right answer, I tested the performance of each answer using two different scenarios in addition to what was provided by @jonrsharpe.

This is the code I used to compare performance between three different solutions using profile :

 import profile arr='test 123456789014' def jonrsharpe(index): global arr for c in range(1,100000,1): a=arr[:-index if index else None] def Cyber(index): global arr for c in range(1,100000,1): a=arr[:len(arr)-index] def shashank(index): global arr for c in range(1,100000,1): a=arr[:-index or None] def testf(): for index in (0,3,6,9): jonrsharpe(index) Cyber(index) shashank(index) if __name__ == '__main__': profile.run("testf()") 

Here is the result:

 ncalls tottime percall cumtime percall filename:lineno(function) 799992 1.629 0.000 1.629 0.000 :0(len) 12 0.021 0.002 0.021 0.002 :0(range) 1 0.006 0.006 0.006 0.006 :0(setprofile) 1 0.000 0.000 4.390 4.390 <string>:1(<module>) 0 0.000 0.000 profile:0(profiler) 1 0.000 0.000 4.396 4.396 profile:0(testf()) 4 2.114 0.529 3.750 0.937 test.py:12(Cyber) 4 0.307 0.077 0.313 0.078 test.py:19(shashank) 1 0.000 0.000 4.390 4.390 test.py:26(testf) 4 0.319 0.080 0.328 0.082 test.py:5(jonrsharpe) 

Another method:

 import time if __name__ == '__main__': arr = '01234567890123456789012345678901234567890123456789'#range(1000) for x in (0, 10, 20, 30,40,49): print 'index=',x start=time.clock() for count in range(1000000): a=arr[:-x if x else None] print 'jonrsharpe=',round(time.clock()-start,4) start=time.clock() for count in range(1000000): a=arr[:len(arr)-x] print 'Cyber =',round(time.clock()-start,4) start=time.clock() for count in range(1000000): a=arr[:-x or None] print 'shashank =',round(time.clock()-start,4) 

Conclusion:

 index= 0 jonrsharpe= 0.4918 Cyber = 0.5341 shashank = 0.4269 index= 10 jonrsharpe= 0.4617 Cyber = 0.5334 shashank = 0.4105 index= 20 jonrsharpe= 0.4271 Cyber = 0.4562 shashank = 0.3493 index= 30 jonrsharpe= 0.4217 Cyber = 0.4548 shashank = 0.3264 index= 40 jonrsharpe= 0.4713 Cyber = 0.8488 shashank = 0.6458 index= 49 jonrsharpe= 0.6159 Cyber = 0.5663 shashank = 0.4312 

Since I will use this line of code millions of times, performance is very important, and @Shashank's solution was a winner in most cases, even if it was a little.

+1
source