# NumPy Array Indexing and Slicing

The elements of a NumPy ndarray can be accessed and modified by indexing and slicing similar to Python’s in-built data structures.

### Indexing

Indexing is the process of accessing items that exist in an iterable or a sequence form.

#### Accessing NumPy array elements:

The `ndarray` elements follow a zero-based index(index value starts from 0).

``````import numpy as np
arr = np.arange(10)
print('first element:', arr[0])
print('second element:', arr[1])
print('last element:', arr[-1])
print('second last element:', arr[-2])``````

Output:

``````array: [0 1 2 3 4 5 6 7 8 9]
first element: 0
second element: 1
last element: 9
second last element: 8``````

#### Negative Indexing:

NumPy and Python both support negative indexing. The negative indexing starts from where the array sequence ends i.e the last element will be the first element in negative indexing having index -1, the second last element has index -2, and so on.

``````arr = np.arange(5,10)
print(arr[-1])
print(arr[-3])
print(arr[-5])``````

Output:

``````9
7
5``````

#### Modify ndarray elements:

The `ndarray` elements can be modified just like Python lists based on the index.

``````arr = np.array([[1, 2, 3, 4 ], [5, 6, 7, 8 ]])
print('array:', arr)
arr[0, 1]= 21
arr[1, 3]= 10
print('modified array:', arr)``````

Output:

``````array: [[1 2 3 4]
[5 6 7 8]]
modified array: [[ 1 21  3  4]
[ 5  6  7 10]]``````

### Slicing

Slicing is the process of retrieving a specific portion or part of an array or list. Slicing can retrieve only the elements that are continuous. For example, let’s consider a list [3, 5, 7, 9]. If we want to retrieve the elements present from index 1 to 3 then, we can go for slicing.

#### Slicing with slice():

The `slice()` function is an in-built Python function used to extract parts of an array. It takes start, stop and step values as arguments and returns a slice object which is passed to the array index to get sliced array.

``````arr = np.arange(7)
so = slice(0, 5, 2)
print('Original array:', arr)
print('Sliced array:', arr[so])``````

Output:

``````Original array: [0 1 2 3 4 5 6]
Sliced array: [0 2 4]``````

#### Slicing with (:)colon:

We can slice a numpy array using colon(:) instead of slice() function(i.e. start:stop:step) directly to the `ndarray` object.

``````arr = np.arange(10)
slice_arr = arr[1: 9: 2]
print('Original array:', arr)
print('Sliced array:', slice_arr)``````

Output:

``````Original array: [0 1 2 3 4 5 6 7 8 9]
Sliced array: [1 3 5 7]``````

#### Slicing with Negative Index:

Just like indexing, slicing can also be done using a negative index. The negative indexing starts from the right side to the left side. Also, if the step size changes to -1 then it can iterate in reverse order(from right to left).

``````arr = np.arange(8)
print(arr[-1: -5: -1])
#Output:
[7 6 5 4]``````

To get all elements of an array except the first few elements:

``````arr = np.arange(6) # arr is [0, 1, 2, 3, 4, 5]
print('Sliced array:', arr[2: ])
#Output:
Sliced array: [2 3 4 5]``````

Leaving just a colon inside the array index (arr[ : ]) means that all elements of an array are included.

To get all elements of an array except some last elements:

``````arr = np.arange(8) # arr is [0, 1, 2, 3, 4, 5, 6, 7]
print('Sliced array:', arr[: -3])
#Output:
Sliced array: [0 1 2 3 4]``````

To get elements of an array between an interval:

``````arr = np.arange(10) # arr is [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print('Sliced array:', arr[4: 8])
#Output:
Sliced array: [4 5 6 7]``````

#### Conditional slicing:

Conditional slicing is a way of slicing where different relational operators (like <, >, ==, etc), and logical operators are used to form condition which is then passed to the array to get the desired slice of the array.

Passing a relational condition to the index of an array.

``````arr = np.arange(10)
print('Original array:', arr)
print('Sliced array:', arr[arr > 4]) #prints elements greater than 4``````

Output:

``````Original array: [0 1 2 3 4 5 6 7 8 9]
Sliced array: [5 6 7 8 9]``````

#### Slicing of Multi-dimensional Array:

Creating a 2-d array to perform slicing operations

``````arr = np.array([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10],
[11, 12, 13, 14, 15], [16, 17, 18, 19, 20]])
print(arr)
#Output:
[[ 1  2  3  4  5]
[ 6  7  8  9 10]
[11 12 13 14 15]
[16 17 18 19 20]]``````

To get any row from the multi-dimensional array:

``````print('third row:', arr[2, :])
print('reverse of first row:', arr[0, ::-1])``````

Output:

``````third row: [11 12 13 14 15]
reverse of first row: [5 4 3 2 1]``````

To get any column from the multi-dimensional array:

``````print('second column:', arr[:, 1])
print('reverse of fourth column:', arr[::-1, 3])``````

Output:

``````second column: [ 2 7 12 17]
reverse of fourth column: [19 14 9 4]``````

Extract a subset of an array:

``````print('values between row 1-3 and column 2-4')
print(arr[0:3,1:4])``````

Output:

``````values between row 1-3 and column 2-4
[[ 2  3  4]
[ 7  8  9]
[12 13 14]]``````

Slicing using compound conditions:

``````print(arr[(arr[:, :] % 2 ==0) & (arr[:, :] > 5)])
#Output:
[ 6  8 10 12 14 16 18 20]``````

Indexing to access multiple elements:

``````print(arr[[0, 2, 3], [1, 3, 4]])
#Output:
[ 2 14 20]``````

So output shows the elements at indices (0,1), (2,3), and (3, 4). The first list contains row numbers and the second list contains column numbers.

We can also get corner values of the 2-d array, i.e (0, 0), (0, 4), (3, 0), and (3, 4).

``````print(arr[[0, 0, 3, 3], [0, 4, 0, 4]])
#Output:
[ 1  5 16 20]``````