List is arguably the most useful and ubiquitous type in Python. One of the reasons it’s so handy is Python slice notation. In short, slicing is a flexible tool to build new lists out of an existing list. Show
Python supports slice notation for any sequential data type like lists, strings, tuples, bytes, bytearrays, and ranges. Also, any new data structure can add its support as well. This is greatly used (and abused) in NumPy and Pandas libraries, which are so popular in Machine Learning and Data Science. It’s a good example of “learn once, use everywhere”. In this article, we will focus on indexing and slicing operations over Python’s lists. Most of the examples we will discuss can be used for any sequential data type. Only mutable assignment and deletion operations are not applicable to immutable sequence types like tuples, strings, bytes, and ranges. Before discussing slice notation, we need to have a good grasp of indexing for sequential types. In Python, list is akin to arrays in other scripting languages(Ruby, JavaScript, PHP). It allows you to store an enumerated set of items in one place and access an item by its position – index. Let’s take a simple example: >>> colors = ['red', 'green', 'blue', 'yellow', 'white', 'black'] Here we defined a list of colors. Each item in the list has a value(color name) and an index(its position in the list). Python uses zero-based indexing. That means, the first element(value ‘red’) has an index 0, the second(value ‘green’) has index 1, and so on. To access an element by its index we need to use square brackets: >>> colors = ['red', 'green', 'blue', 'yellow', 'white', 'black'] >>> colors[0] 'red' >>> colors[1] 'green' >>> colors[5] 'black' Negative indexesUsing indexing we can easily get any element by its position. This is handy if we use position from the head of a list. But what if we want to take the last element of a list? Or the penultimate element? In this case, we want to enumerate elements from the tail of a list. To address this requirement there is negative indexing. So, instead of using indexes from zero and above, we can use indexes from -1 and below. In negative indexing system -1 corresponds to the last element of the list(value ‘black’), -2 to the penultimate (value ‘white’), and so on. >>> colors = ['red', 'green', 'blue', 'yellow', 'white', 'black'] >>> colors[-1] 'black' >>> colors[-2] 'white' >>> colors[-6] 'red' AssignmentBefore we used indexing only for accessing the content of a list cell. But it’s also possible to change cell content using an assignment operation: >>> basket = ['bread', 'butter', 'milk'] >>> basket[0] = 'cake' >>> basket ['cake', 'butter', 'milk'] >>> basket[-1] = 'water' >>> basket ['cake', 'butter', 'water'] We can freely use positive or negative indexing for assignment. DeletionWe can also easily delete any element from the list by using indexing and >>> basket = ['bread', 'butter', 'milk'] >>> del basket[0] >>> basket ['butter', 'milk'] >>> del basket[1] >>> basket ['butter'] Indexing for other Sequential TypesRead-only indexing operations work perfectly well for all sequential types. But assignment and deletion operations are not applicable to immutable sequential types. Slice NotationAs it was shown, indexing allows you to access/change/delete only a single cell of a list. What if we want to get a sublist of the list. Or we want to update a bunch of cells at once? Or we want to go on a frenzy and extend a list with an arbitrary number of new cells in any position? Those and lots of other cool tricks can be done with slice notation. Let’s look at this subject. Basic Usage of SlicesLet’s create a basic list: >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] What if we want to take a sublist from the >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> some_nums = nums[2:7] >>> some_nums [30, 40, 50, 60, 70] So, here is our first example of a slice: 2:7. The
full slice syntax is: start:stop:step. In our example We did not use With slices we can extract an arbitrary part of a list, e.g.: >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[0:4] [10, 20, 30, 40] Here we start from the first element(index Taking n first elements of a listSlice notation allows you to skip any
element of the full syntax. If we skip the >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[:5] [10, 20, 30, 40, 50] So, nums[:5] is equivalent to nums[0:5]. This combination is a handy shortcut to take n first elements of a list. Taking n last elements of a listNegative indexes allow us to easily take n-last elements of a list: >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[-3:] [70, 80, 90] Here, the We can freely mix negative and positive indexes in >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[1:-1] [20, 30, 40, 50, 60, 70, 80] >>> nums[-3:8] [70, 80] >>> nums[-5:-1] [50, 60, 70, 80] Taking all but n last elements of a listAnother good usage of negative indexes: >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[:-2] [10, 20, 30, 40, 50, 60, 70] We take all but the last two elements of original list. Taking every nth-element of a listWhat if we want to have only every 2-nd element of >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[::2] [10, 30, 50, 70, 90] Here we omit >>> nums[1::2] [20, 40, 60, 80] And if we don’t want to include some elements at the end, we can also add the >>> nums[1:-3:2] [20, 40, 60] Using Negative Step and Reversed ListWe can use a negative >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[::-1] [90, 80, 70, 60, 50, 40, 30, 20, 10] Negative Due to this peculiarity, >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[-2::-1] [80, 70, 60, 50, 40, 30, 20, 10] So, we start from the We can use >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[-2:1:-1] [80, 70, 60, 50, 40, 30] We use It’s a bit baffling that
with a negative Of course, we can use an arbitrary negative >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[-2:1:-3] [80, 50] Slice and CopyingOne important thing to notice – is that list slice creates a shallow copy of the initial list. That means, we can safely modify the new list and it will not affect the initial list: >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> first_five = nums[0:5] >>> first_five[2] = 3 >>> first_five [10, 20, 3, 40, 50] >>> nums [10, 20, 30, 40, 50, 60, 70, 80, 90] Despite our mutating the element under index
There is the shortest form of slice notation – just colons nums[:]. >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums_copy = nums[:] >>> nums_copy[0] = 33 >>> nums_copy [33, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums [10, 20, 30, 40, 50, 60, 70, 80, 90] It creates a shallow copy of the whole list and is a good shorthand when you need a copy of the original list. Slice ObjectBut what if we want to use the same slice over and over again. Is there a way to create a slice object instead of using just the syntactic form? This can be done using >>> five_items_after_second = slice(2, 2 + 5) >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> colors = ['red', 'green', 'blue', 'yellow', 'white', 'black', 'silver'] >>> nums[five_items_after_second] [30, 40, 50, 60, 70] >>> colors[five_items_after_second] ['blue', 'yellow', 'white', 'black', 'silver']
>>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> all_but_two_last = slice(None, -2) >>> nums[all_but_two_last] [10, 20, 30, 40, 50, 60, 70] >>> reversed = slice(None, None, -1) >>> nums[reversed] [90, 80, 70, 60, 50, 40, 30, 20, 10] Slice AssignmentPython supports slice assignment operation, which allows us to make a bunch of neat operations over an existing list. Unlike previous slice operations, these mutate the original object in place. That’s why they are not applicable to immutable sequential types. Substitute part of a listSlice assignment allows you to update a part of a list with new values: >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[:4] = [1,2,3,4] >>> nums [1, 2, 3, 4, 50, 60, 70, 80, 90] Here we do not change the number of elements in the list. Only some list values are updated. Replace and Resize part of the listWe can replace part of a list with a bigger chunk instead: >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[:4] = [1,2,3,4,5,6,7] >>> nums [1, 2, 3, 4, 5, 6, 7, 50, 60, 70, 80, 90] In this case we extend the original list. It’s also possible to replace a bigger chunk with a smaller number of items: >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[:4] = [1] >>> nums [1, 50, 60, 70, 80, 90] Replace Every n-th ElementAdding >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[::2] = [1,1,1,1,1] >>> nums [1, 20, 1, 40, 1, 60, 1, 80, 1] Using slice assignment with >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[::2] = [1,1,1] Traceback (most recent call last): File "", line 1, in ValueError: attempt to assign sequence of size 3 to extended slice of size 5 We can also use negative >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[::-2] = [1,2,3,4,5] >>> nums [5, 20, 4, 40, 3, 60, 2, 80, 1] By providing >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> nums[1:5:2] = [2, 4] >>> nums [10, 2, 30, 4, 50, 60, 70, 80, 90] Slice DeletionWe can also use >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> del nums[3:7] >>> nums [10, 20, 30, 80, 90] Here we’ve removed a bunch of elements in the middle of We can also provide >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> del nums[::2] >>> nums [20, 40, 60, 80] With the full syntax, we can set boundaries for the elements to be removed: >>> nums = [10, 20, 30, 40, 50, 60, 70, 80, 90] >>> del nums[1:7:2] >>> nums [10, 30, 50, 70, 80, 90] So, we start deletion from 20(index 1) and remove each 2-nd element till the value 80(index 7). And because slice deletion mutates the underlying object, it’s not applicable to immutable sequential types. SummaryWe discussed two key list operations: indexing and slicing. Both concepts are crucial to efficient Python use. This article prepared background for tackling indexing
and slicing in If you are still a beginner, here is the list of libraries and tools which may help you to start off with Machine Learning and AI. What is meant by slicing a string?Definition. Slicing is the process of obtaining a portion (substring) of a string by using its indices. Given a string, we can use the following template to slice it and obtain a substring: string[start:end] start is the index from where we want the substring to start.
What is meant by slicing operator?The slice operator [n:m] returns the part of the string starting with the character at index n and go up to but not including the character at index m. Or with normal counting from 1, this is the (n+1)st character up to and including the mth character.
How does slicing work in Python list?With this operator, one can specify where to start the slicing, where to end, and specify the step. List slicing returns a new list from the existing list. If Lst is a list, then the above expression returns the portion of the list from index Initial to index End, at a step size IndexJump.
|