## What is Numpy Arrays in Python

A NumPy array is a grid of values, all of the same type, and is indexed by a tuple of non-negative integers. The number of dimensions is the rank of the array; the shape of an array is a tuple of integers giving the size of the array along each dimension.

## Installation

Firstly, to start working with NumPy, we need to install it, which can be easily done with pip:

`pip3 install numpy` Then, import the library before starting your work:

```import numpy as np
```

## NumPy arrays

The core NumPy object is an n-dimensional array, also known as ndarray. The simplest way to create a NumPy array is to convert a Python list:

```import numpy as np
num = np.array([10, 20, 30, 40, 50])
print(num)
print(type(num))```

#### Output In the above example, num is a one-dimensional array that is treated as a vector. As we can see, when printed, it is rendered without commas, instead of Python lists.

Additionally, we can make a two-dimensional Numpy array from the relating Python list. Two-and more dimensional arrays are treated as matrices.

```num_2 = np.array([[10, 20, 10],
[20, 10, 20]])

print(num_2)
```

#### Output ## NumPy arrays vs. Python lists

As we know, NumPy arrays is similar to a Python built-in list data type. However, there are a couple of crucial differences:

• Unlike Python lists, NumPy arrays can just contain elements of a similar kind, typically numbers, because of the specifics of application fields.
• NumPy arrays are significantly more memory-effective and a lot quicker than Python lists when working with huge datasets.
• Arithmetic operations vary when executed on Python lists or NumPy arrays.

Let’s have a look at arithmetic operations that can be applied both to arrays and to lists. All differences in them can be clarified by the way that Numpy arrays are created for computing and treated as vectors and matrices, while Python lists are a datatype made just to store information.

To show it, we’ll create two lists and two arrays containing similar elements:

```list_1 = [10, 20, 30, 40]
array_1 = np.array(list_1)

list_2 = [1, 2, 3, 4]
array_2 = np.array(list_2)```

Let’s find their sum. The addition of two arrays returns their sum as when we add two vectors.

`print(array_1 + array_2)`

For this reason, we can’t add up arrays of different lengths, a ValueError will appear.

```array_c = np.array([111, 222])
print(array_a + array_c)```

#### Output When we try to add a list and an array, the former is converted to an array, so the result is also a sum of vectors.

`print(list_1 + array_1)`

#### Output Similarly, if we try to multiply a list by n, we’ll get the list repeated n times, while with an array, each element will be multiplied by n:

```print(list_1 * 3)
print(array_1 * 3)```

#### Output ## Array range and evenly spaced array

The main function that assists with creating arrays in NumPy, is np.arange(). It is like the built-in range() generator of numbers, yet np.arange() returns an array. Let’s understand with the help of an example:

```array1 = np.arange(5)
print(array1)```

You can likewise create an array by indicating a start element, a stop element, and a step: np.arange(start, stop, step). The default step value is 1. Note that the start element is included for the range and the stop element isn’t.

```array2 = np.arange(1, 5)
array3 = np.arange(1, 5, 0.5)
print(array2)
print(array3)```

#### Output If you need all the elements in your array to be space uniformly, np.linspace() can help you. It takes the beginning(start) value, the end value, and the num parameter which is the total number of elements. The default value of num is 50, so in the second example underneath there will be 50 elements in the array array5, equally separated between in the range of 10 and 12. Instead of the np.arange() function, the end value in np.linspace() is always included for the array.

```array4 = np.linspace(10, 12, num=5)
array5 = np.linspace(10, 12)
print(array4)
print(array5)```

#### Output ## Arrays filled with ones and zeros

Some of the time we need an array consisting of just zeroes or just ones. In NumPy, there are simple approaches to make them. np.zeros() and np.ones() make new dimensioned arrays loaded up with the corresponding values.

```array6 = np.ones((2, 2))
array7 = np.zeros(5)
print(array6)
print(array7)```

#### Output The np.zeros_like() and np.ones_like() functions are similar to the previous ones, but they return an array of ones or zeros with the same shape and type as the given arrays.

```x = np.array([[1, 1, 1], [2, 2, 2]])
y = np.array([1, 2, 3, 4, 5])
array8 = np.ones_like(x)
array9 = np.zeros_like(y)
print(array8)
print(array9)```

#### Output ## Converting NumPy arrays to Python lists

Finally, when you don’t need to work with arrays anymore, you can easily transform them into lists. NumPy provides the array.tolist() function.

```array10 = np.array([[10, 20], [30, 40]])
lst1 = array10.tolist()
print(lst1)```

If we attempt to use the list(array) function on numpy arrays, it will also return a list but its inner elements will be numpy arrays.

```array11 = np.array([[10, 20], [30, 40]])
lst2 = list(array11)
print(lst2)
print(type(lst2))```

#### Output ## NumPy Array Indexing Presently, when we can create arrays, it’s time to learn how to get access to their elements. Much the same as with Python lists, we can access to the elements using indices. If you utilize a one-dimensional array in your program, there’s no difference with how list lists indices work. Although, when you face a n-dimensional array, mind some crucial operations.

How about we understand with the help of an example.

```array12 = np.array([[1, 12, 31], [4, 45, 64], [0, 7, 89]])
print(array12[2, 2])
print(array12)```

Firstly, we made a two-dimensional array. Suppose we are keen on getting the last value. The possibility of multidimensional indexing is very simple: if you have two dimensions, the first value adressess to the row of your array, the second one addresses to the index of the value you are scanning for. You can see that the result of array12[2, 2] and array12 is the equivalent. The first case is more effective, nonetheless, because when we compose array12, another temporary array is made after the first index that is in this way indexed by 2.

Thus, if you have three dimensions, you have to print three values to execute multidimensional indexing, and so forth. Let’s check three-dimensional example:

```array13 = np.array([[[10, 20, 31], [40, 45, 6], [10, 75, 89]]])
print(array13[0, 1, 1])
print(array13)```

If you print an index that is out of the bounds, it’ll cause an error in your program.

```array13 = np.array([[[10, 20, 31], [40, 45, 6], [10, 75, 89]]])
print(array13[0, 1, 1])
print(array13)```

#### Output ## Negative indexing

Use negative indexing to access an array from the end.

```arr = np.array([[10,20,30,40,50], [60,70,80,90,100]])

print('Last element ', arr[1, -1])```

## NumPy Array Slicing NumPy arrays can likewise be sliced like lists in Python. Slicing a one-dimensional array is equivalent to slicing a Python list, so our primary task is to understand how to slice n-dimensional arrays. Consider the following example:

```array14 = np.array([[10, 11, 12],
[13, 14, 15],
[16, 17, 18],
[19, 20, 21]])
print(array14[1:3, 1])```

We start with creating a two-dimensional array array14 with four rows. At the point when we compose array14[1:3, 1], the initial segment addresses to the slice of the rows to be considered, at that point the second part picks an element of each row. Accordingly, we have another one-dimensional array.

Let’s have a look at some examples. array15 below is a three-dimensional array. Much the same as in Python, we can utilize the negative index to choose elements from the end: the last two-dimensional exhibit [[11, 12, 13, 14, 15], [16, 17, 18, 19, 20]] for this situation. At that point we simply make a full duplicate of the array with the help of the : operator, and finally in each row we choose a specific slice.

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

#### Output In array16 we extract every row and element with a given step.

```array16 = np.array([[1, 2, 3, 4, 5],
[5, 4, 3, 2, 1],
[6, 7, 8, 9, 10],
[10, 9, 8, 7, 6],
[11, 12, 13, 14, 15]])
print(array16[::2, ::2])```

#### Output As far as you can see, slicing operations are the same as with Python lists but here we apply them taking the dimensions into account. This can lead to some errors, especially with high-dimensional arrays, so we need to be very careful.

Hence, we can conclude:

• create arrays using different methods,
• transform arrays into lists,
• index and slice multidimensional arrays.

Let’s try to solve a problem

The input contains two integers: the first one is a number of rows and columns in the two-dimensional square array you should create. The second one is an integer your array should be filled with – zero or one. Print the array.

Sample Input 1:

8
1
Sample Output 1:

[[1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1. 1. 1.]]
Sample Input 2:

3
0
Sample Output 2:

[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]

```import numpy as np
n, fill = int(input()), float(input())
print(np.full((n, n), fill))```

#### Output 