17  Indexing and slicing

Author

Andres Patrignani

Published

January 5, 2024

Indexing and slicing are fundamental concepts used to retrieve and modify data within sequences like strings, lists, and arrays. Python uses zero-based indexing, meaning that the first element of any sequence is accessed with index 0, not 1. Indexing allows you to access individual elements, while slicing lets you access a subset, or a slice, of a sequence.

Note

0-based indexing offers some practical advantages in terms of memory management and algorithmic efficiency. This indexing system simplifies pointer arithmetic, as the index corresponds directly to the offset from the base address in memory. With 1-based indexing, an extra subtraction is needed. There is also a historical reason due to the influence of earlier programming languages, like C, that were also 0-based indexing.

Syntax for indexing and slicing one-dimensional arrays

# Indexing a one-dimensional array
element = array[index]

# Slicing a one-dimensional array
sub_array = array[start_index:end_index:step]

Omitting start_index (e.g., array[:end_index]) slices from the beginning to end_index.

Omitting end_index (e.g., array[start_index:]) slices from start_index to the end of the array.

# Generate intengers from 0 to the specified number (non-inclusive)
numbers = list(range(10)) 
print(numbers)

# Find the first element of the list (indexing operation)
print(numbers[0])

# First and second element
print(numbers[0:2])  

# Print last three elements
print(numbers[-3:]) 

# All elements (from 0 and on)
print(numbers[0:])

# Every other element (specifying the total number of element)
print(numbers[0:10:2]) 

# Every other element (without specifying the total number of elements)
print(numbers[0:-1:2])

# Print the first 3 elements
print(numbers[:3])

# Slice from the 4th to the next-to-last element
print(numbers[4:-1]) 

# Print the last item of the list
print(numbers[-1])
print(numbers[len(numbers)-1])
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0
[0, 1]
[7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 2, 4, 6, 8]
[0, 2, 4, 6, 8]
[0, 1, 2]
[4, 5, 6, 7, 8]
9
9

Syntax for indexing and slicing two-dimensional arrays

# Indexing a two-dimensional array
element = array[row_index][column_index]

# Slicing a two-dimensional array (with step)
sub_array = array[row_start:row_end:row_step, column_start:column_end:column_step]

Omitting row_start (e.g., array[:row_end, :]) slices from the beginning to row_end in all columns. Here “all columns” is represented by the : operator. Similarly you can use : to represent all rows.

Omitting row_end (e.g., array[row_start:, :]) slices from row_start to the end in all columns.

import numpy as np

# Indexing and slicing a two-dimensional array
np.random.seed(0)
M = np.random.randint(0,10,[5,5])
print(M)

# Write five python commands to obtain:
# top row
# bottom row
# right-most column
# left-most column
# upper-right 3x3 matrix
[[5 0 3 3 7]
 [9 3 5 2 4]
 [7 6 8 8 1]
 [6 7 7 8 1]
 [5 9 8 9 4]]
# Solutions

# Top row
print('Top row')
print(M[0,:]) # Preferred
print(M[:1][0])
print(M[0])
print('')

# Bottom row
print('Bottom row')
print(M[-1,:]) # Preferred
print(M[-1])
print(M[4,:]) # Requires knowing size of array in advance
print('')

# Right-most column
print('Right-most column')
print(M[:,-1])
print('')

# Left-most column
print('Left-most column')
print(M[:,0])
print('')

# Upper-right 3x3 matrix
print('Upper 3x3 matrix')
print(M[0:3,M.shape[1]-3:M.shape[1]])  # More versatile
print(M[0:3,2:M.shape[1]])
Top row
[5 0 3 3 7]
[5 0 3 3 7]
[5 0 3 3 7]

Bottom row
[5 9 8 9 4]
[5 9 8 9 4]
[5 9 8 9 4]

Right-most column
[7 4 1 1 4]

Left-most column
[5 9 7 6 5]

Upper 3x3 matrix
[[3 3 7]
 [5 2 4]
 [8 8 1]]
[[3 3 7]
 [5 2 4]
 [8 8 1]]

References

Source: https://stackoverflow.com/questions/509211/understanding-slice-notation