Slicing Arrays¶
Slicing extracts contiguous subsequences from arrays using start:stop:step syntax.
Mental Model
A slice is a window into the original array's memory -- it selects a contiguous range without copying data. The start:stop:step syntax works the same as Python lists, but NumPy slices extend to multiple dimensions with comma-separated ranges. Because slices return views, modifying a slice modifies the original.
1D Array Slicing¶
Basic slicing works identically for lists and NumPy arrays.
1. Range Slice¶
```python import numpy as np
def main(): a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] b = np.array(a) print(f"{a = }") print(f"{b = }", end="\n\n")
print(f"{a[1:2] = }")
print(f"{b[1:2] = }")
if name == "main": main() ```
Output:
a[1:2] = [1]
b[1:2] = array([1])
2. From Start¶
```python import numpy as np
def main(): a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] b = np.array(a)
print(f"{a[:5] = }")
print(f"{b[:5] = }")
if name == "main": main() ```
Output:
a[:5] = [0, 1, 2, 3, 4]
b[:5] = array([0, 1, 2, 3, 4])
3. To End¶
```python import numpy as np
def main(): a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] b = np.array(a)
print(f"{a[1:] = }")
print(f"{b[1:] = }")
if name == "main": main() ```
Output:
a[1:] = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b[1:] = array([1, 2, 3, 4, 5, 6, 7, 8, 9])
Step Slicing¶
The third parameter specifies the step size.
1. Step from Start¶
```python import numpy as np
def main(): a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] b = np.array(a)
print(f"{a[:5:2] = }")
print(f"{b[:5:2] = }")
if name == "main": main() ```
Output:
a[:5:2] = [0, 2, 4]
b[:5:2] = array([0, 2, 4])
2. Step to End¶
```python import numpy as np
def main(): a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] b = np.array(a)
print(f"{a[1::2] = }")
print(f"{b[1::2] = }")
if name == "main": main() ```
Output:
a[1::2] = [1, 3, 5, 7, 9]
b[1::2] = array([1, 3, 5, 7, 9])
3. Reverse Array¶
```python import numpy as np
def main(): a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] b = np.array(a)
print(f"{a[::-1] = }")
print(f"{b[::-1] = }")
if name == "main": main() ```
Output:
a[::-1] = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
b[::-1] = array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
2D Array Slicing¶
Slicing 2D arrays operates on rows by default.
1. Row Range¶
```python import numpy as np
def main(): a = [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]] b = np.array(a)
print("a[:3]")
print(a[:3], end="\n\n")
print("b[:3]")
print(b[:3])
if name == "main": main() ```
2. Row with Step¶
```python import numpy as np
def main(): a = [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]] b = np.array(a)
print("a[:4:2]")
print(a[:4:2], end="\n\n")
print("b[:4:2]")
print(b[:4:2])
if name == "main": main() ```
3. Reverse Rows¶
```python import numpy as np
def main(): a = [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]] b = np.array(a)
print("a[::-1]")
print(a[::-1], end="\n\n")
print("b[::-1]")
print(b[::-1])
if name == "main": main() ```
Multi-Axis Slicing¶
NumPy allows simultaneous slicing across multiple axes.
1. Row Slice Only¶
```python import numpy as np
def main(): a = [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]] b = np.array(a)
try:
print(a[1, :])
except TypeError as e:
print(f"List error: {e}")
print("b[1, :]")
print(b[1, :])
if name == "main": main() ```
Output:
List error: list indices must be integers or slices, not tuple
b[1, :]
[1 2 3]
2. Column Slice Only¶
```python import numpy as np
def main(): a = [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]] b = np.array(a)
try:
print(a[:, 1])
except TypeError as e:
print(f"List error: {e}")
print("b[:, 1]")
print(b[:, 1])
if name == "main": main() ```
Output:
List error: list indices must be integers or slices, not tuple
b[:, 1]
[1 2 3 4 5]
3. Both Axes¶
```python import numpy as np
mat = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) print(mat[0:2, 1:]) ```
Output:
[[2 3]
[5 6]]
Views Are Fast but Dangerous
Slices return views (no data copy), which makes them fast and memory-efficient. But modifying a view modifies the original array:
python
a = np.arange(10)
view = a[2:5]
view[0] = 999
print(a[2]) # 999 — original changed!
Use .copy() when you need an independent copy: safe = a[2:5].copy().
Exercises¶
Exercise 1.
Given a = np.arange(20), use slicing to extract every third element starting from index 2. Also extract the last 5 elements in reverse order using a single slice.
Solution to Exercise 1
import numpy as np
a = np.arange(20)
every_third = a[2::3]
print(f"Every third from index 2: {every_third}")
last_five_reversed = a[-1:-6:-1]
print(f"Last 5 reversed: {last_five_reversed}")
Exercise 2.
Create a 5x6 matrix M = np.arange(30).reshape(5, 6). Use multi-axis slicing to extract the 3x2 submatrix consisting of rows 1--3 and columns 4--5. Also extract every other row and every other column.
Solution to Exercise 2
import numpy as np
M = np.arange(30).reshape(5, 6)
submatrix = M[1:4, 4:6]
print(f"Submatrix (rows 1-3, cols 4-5):\n{submatrix}")
every_other = M[::2, ::2]
print(f"Every other row and col:\n{every_other}")
Exercise 3.
Given a 2D array, demonstrate that a NumPy slice returns a view by modifying a sliced subarray and checking that the original is also modified. Then repeat with .copy() and show the original is not modified.
Solution to Exercise 3
import numpy as np
original = np.arange(12).reshape(3, 4)
view = original[0:2, 0:2]
view[0, 0] = 999
print(f"Original after view modification:\n{original}")
# original[0, 0] is now 999
original2 = np.arange(12).reshape(3, 4)
copy = original2[0:2, 0:2].copy()
copy[0, 0] = 888
print(f"Original after copy modification:\n{original2}")
# original2[0, 0] is still 0