```
In [3]:
```%pylab inline

```
```

J.R. Johansson and P.D. Nation

For more information about QuTiP see http://qutip.org

```
In [5]:
```a=[1,2,3]
a=a+1

```
```

Instead we would have to do

```
In [6]:
```for k in range(3):
a[k]=a[k]+1

**arrays** as our preferred data structure.

**vectorization** leads to very fast Python code, and can replace many of the for-loops that you would have use if you coded a problem using lists. As a general rule, **minimizing the number of for-loops maximizes the performance of your code**. To start using arrays, we can start with a simple list and use it as an argument to the array function

```
In [7]:
```from numpy import *
a=array([1,2,3,4,5,6])
print(a)

```
```

```
In [8]:
```a=array([2.0,4.0,8.0,16.0])
b=array([0,1+0j,1+1j,2-2j])
c=array(['a','b','c','d'])
print(a)
print(b)
print(c)

```
```

In general there are three different ways of creating arrays in Python:

First create a list and then call the array function using the list as an input argument.

Use NumPy functions that are designed to create arrays:

**zeros, ones, arange, linspace**.Import data into Python from file.

```
In [9]:
```output=[n for n in range(10)]
print(output)

```
```

This code is doing the exact same thing as the longer expression

```
In [10]:
```output=[]
for n in range(10):
output.append(n)
print(output)

```
```

We could turn this into an array quite easy

```
In [11]:
```array(output)

```
Out[11]:
```

Or, we can save even more space and create the list inside of the array function:

```
In [12]:
```array([n for n in range(10)])

```
Out[12]:
```

This can also be used to create more complicated arrays

```
In [13]:
```array([2.0*k**0.563 for k in range(0,10,2)])

```
Out[13]:
```

```
In [14]:
```zeros(5)

```
Out[14]:
```

```
In [15]:
```ones(10)

```
Out[15]:
```

```
In [16]:
```arange(5)

```
Out[16]:
```

```
In [17]:
```arange(0,10,2)

```
Out[17]:
```

```
In [18]:
```linspace(0,10,20) #makes an array of 20 points linearly spaced from 0 to 10

```
Out[18]:
```

```
In [19]:
```linspace(-5,5,15) #15 points in range from -5 to 5

```
Out[19]:
```

**arrays can only hold one type of data** (integers, floats, strings, complex). If we try to combine different types of data, then the array function will **upcast** the data in the array such that it all has the same type

```
In [20]:
```array([1,2,3.14]) # [int,int,float] -> [float,float,float]

```
Out[20]:
```

```
In [21]:
```array([1.0,1+1j,'hello']) #array data is upcast to strings

```
Out[21]:
```

`dtype`

("data type") keyword argument. Frequently used dtypes are: `int, float, complex, bool, str, object`

, etc. For example, to convert a list of integers to floats we can write

```
In [22]:
```array([1,2,3,4,5],dtype=float)

```
Out[22]:
```

```
In [23]:
```arange(2,10,2,dtype=complex)

```
Out[23]:
```

```
In [24]:
```array([k for k in range(10)],dtype=str)

```
Out[24]:
```

**we can not remove or add elements to an array once it has been created**. Therefore, we must know the size of the array before creating it.

**elementwise**, which means that each element gets acted on in the same way. This is an example of **vectorization**. For example:

```
In [25]:
```a=array([1,2,3,4])
5.0*a #This gets upcasted because 5.0 is a float

```
Out[25]:
```

```
In [26]:
```5*a**2-4

```
Out[26]:
```

Recall that none of these operations worked on Python lists.

```
In [27]:
```x=linspace(-pi,pi,10)
sin(x)

```
Out[27]:
```

```
In [28]:
```x=array([x**2 for x in range(4)])
sqrt(x)

```
Out[28]:
```

```
In [29]:
```x=array([2*n+1 for n in range(10)])
sum(x) #sums up all elements in the array

```
Out[29]:
```

```
In [30]:
```a=array([0,-1,2,-3,4])
print(a<0)

```
```

`True/False`

) values indicating whether a given element is less than zero. Or, for example, we can find all of the odd numbers in an array.

```
In [31]:
```a=arange(10)
print((mod(a,2)!=0))

```
```

```
In [32]:
```a=arange(20)
a[3::3]

```
Out[32]:
```

Now lets set each of these elements equal to -1.

```
In [33]:
```a[3::3]=-1
print(a)

```
```

We can also slice the array so that it returns the original array in reverse

```
In [34]:
```a=arange(10)
a[::-1]

```
Out[34]:
```

`True`

.

```
In [35]:
```a=linspace(-10,10,20)
print(a[a<=-5])

```
```

We must be careful though. Checking for multiple conditionals is not allowed

```
In [36]:
```print(a[-8<a<=-5])

```
```

`True/False`

values and return just a single value.

```
In [42]:
```N=20
# generate a list from 2->N
numbers = []
for i in range(2,N+1): # This can be replaced by array
numbers.append(i)
# Run Seive of Eratosthenes algorithm marking nodes with -1
for j in range(N-1):
if numbers[j]!=-1:
p=numbers[j]
for k in range(j+p,N-1,p): # This can be replaced by array
numbers[k]=-1
# Collect all elements not -1 (these are the primes)
primes = []
for i in range(N-1): # This can be replaced by array
if numbers[i]!=-1:
primes.append(numbers[i])
print(primes)

```
```

Using arrays instead of lists simplifies the code:

```
In [41]:
```N=20
# generate a list from 2->N
numbers=arange(2,N+1) # replaced for-loop with call to arange
# Run Seive of Eratosthenes algorithm
# by marking nodes with -1
for j in range(N-1):
if numbers[j]!=-1:
p=numbers[j]
numbers[j+p:N-1:p]=-1 # replaced for-loop by slicing array
# Collect all elements not -1 (these are the primes)
primes=numbers[numbers!=-1] # Used conditional statement to get elements !=-1
print(primes)

```
```

```
In [1]:
```from IPython.core.display import HTML
def css_styling():
styles = open("styles/style.css", "r").read()
return HTML(styles)
css_styling()

```
Out[1]:
```

```
In [ ]:
```