# List

List is one of the **compound** data types in Python. Lists can group together elements. &#x20;

A list is written as a **comma-separated**  `,` elements (values or items) between **square brackets** `[]`. Lists might contain elements of different types, but usually the elements all have the same type.

```python
# empty list
my_list = []

# list of integers
my_list = [1, 2, 3, 4]

# list of strings
my_list = ['Krakow', 'Warsaw', 'Poznan', 'Wroclaw']

# list with mixed datatypes
my_list = ['Krakow', 2, 3.86, True]
```

Python lists are:

* Lists can be empty
* Lists can have any elements
* Lists are ordered
* List elements can be accessed by index
* Lists can be nested to any arbitrary depth
* Lists are mutable, i.e. they can be modified after they are created

## Lists can be empty

An empty list can be created by assigning empty **square brackets** to an identifier.

```python
# empty list
my_list = []
```

## Lists can have any elements

Lists can contain a single datatype or a mixture of datatypes.

```python
# list of integers
my_list = [1, 2, 3, 4]

# list of floats
my_list = [1.2, 2.4, 3.6, 4.8]

# list of strings
my_cities = ['Krakow', 'Warsaw', 'Poznan', 'Wroclaw']

# list with mixed datatypes
my_list = ['Krakow', 2, 3.86, True]
```

## Lists are ordered

The order of elements in a list is important. Two lists are not the same if the elements within a list are same but in a different order.

```python
list_01 = [1, 2, 3, 4]
list_02 = [4, 3, 2, 1]
```

These two lists have the same elements but in **different order**

{% tabs %}
{% tab title="Code" %}

```python
list_01 == list_02
```

{% endtab %}

{% tab title="Output" %}

```python
False
```

{% endtab %}
{% endtabs %}

You can use is keyword too.

{% tabs %}
{% tab title="Code" %}

```python
list_01 is list_02
```

{% endtab %}

{% tab title="Output" %}

```python
False
```

{% endtab %}
{% endtabs %}

## List elements can be accessed by index

You can use the index operator of **square brackets**`[]` to access an element in a list. In Python, index starts from 0.&#x20;

Index number should be an integer, otherwise it raises `TypeError`. Python will raise an `IndexError` if the index element is outside of the length of the list minus one.

```python
my_cities = ['Krakow', 'Warsaw', 'Poznan', 'Wroclaw']
```

### Positive Indexing

The indices for the elements are as follow:

![Positive Index](https://2210269271-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2JwSQyF92eIZDOl88R%2F-M2T02U4TM1mVXMYcg2Z%2F-M2T2A8SnK22uIU7GjFP%2Fimage.png?alt=media\&token=ec2b87f3-3c85-431e-ac23-f5b0d4f99c14)

You can access each element by writing the name of the **`list`** followed by **square brackets** `[]` and **`index number`**&#x6F;f the element.

```python
my_cities[0]
# OUTPUT:
'Krakow'

my_cities[3]
# OUTPUT:
'Wroclaw'
```

### Negative indexing

Python allows negative indexing for elements in a list. Negative index counts from the end of the list. **-1** is the index of last element, **-2** is the index of second from last element, so on.

![Negative Index](https://2210269271-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2JwSQyF92eIZDOl88R%2F-M2T6R_VQDKdePTgEzq6%2F-M2TL3LGD8zUXxdcvgZD%2Fimage.png?alt=media\&token=ed34c3a1-0ea8-4fd4-89d6-bb4f8933a3c7)

You can access elements in a list using negative index.&#x20;

```python
my_cities[-1]
# OUTPUT:
'Wroclaw'

my_cities[-3]
# OUTPUT:
'Warsaw'
```

### List slicing in Python

Slicing of a list needs two indices: `start index` and `end index` separated by a **colon `:`**

All slice operations return a new list containing the requested elements. This means that the following slice returns a [shallow copy](https://docs.python.org/3/library/copy.html#shallow-vs-deep-copy) of the list.

```python
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]
```

You create a new list using slice operations. **Square brackets** `[]` with **colon** `:` will select all elements in the list and assign it to a new list

```python
new_list = my_list[:]
```

Let's compare `my_list` with `new_list`

{% tabs %}
{% tab title="== comparison" %}

```python
my_list == new_list
```

{% endtab %}

{% tab title="Output 1" %}

```python
True
```

{% endtab %}

{% tab title="is keyword comparison" %}

```python
my_list is new_list
```

{% endtab %}

{% tab title="Output 2" %}

```python
False
```

{% endtab %}
{% endtabs %}

While comparing `new_list` with `my_list` with `==`, Python returns `True` but comparison with Python keyword `is` returns `False`. `==` compares the orders of elements in the`my_list` and `new_list`but Python`is` keyword is referencing memory locations of the `my_list` and `new_list` which are different and returns `False.`

#### Slicing to select/filter elements

Let's say you want to get the 2nd to 7th elements. Our start index is 1 and end index is 7 (End index returns the index before index 7, so in this case until index 6).

{% tabs %}
{% tab title="Code" %}

```python
# value 2nd to 7th
start_index = 1
end_index = 7
my_list[start_index:end_index]
my_list[1:7] # you can write it this way too.
```

{% endtab %}

{% tab title="Output" %}

```python
[3, 4, 5, 5, 7, 8]
```

{% endtab %}
{% endtabs %}

Lists usually start counting from left to right. Empty start index location means select/filter elements from the start.

{% tabs %}
{% tab title="Code" %}

```python
# value beginning to 6th
my_list[:6]
```

{% endtab %}

{% tab title="Output" %}

```python
[2, 3, 4, 5, 5, 7]
```

{% endtab %}
{% endtabs %}

Empty end index location means select/filter the elements from start index to the last element in the list.&#x20;

{% tabs %}
{% tab title="Code" %}

```python
# value 6th to the end
my_list[5:]
```

{% endtab %}

{% tab title="Output" %}

```python
[7, 8, 1, 5, 6, 2, 9, 0]
```

{% endtab %}
{% endtabs %}

You can use a mixture of index and negative index together. For example; let's select 2nd element from start until 3rd element from the end. \
2nd element has index of **1** (Python starts zero index) and 3rd element from end has index of **-2**, end index returns the (index - 1), meaning index is bigger by one number.

{% tabs %}
{% tab title="Code" %}

```python
# value 2nd from start until 2nd from the end
my_list[1:-2]
```

{% endtab %}

{% tab title="Output" %}

```python
[3, 4, 5, 5, 7, 8, 1, 5, 6, 2]
```

{% endtab %}
{% endtabs %}

### Stride

You can specify a stride—either positive or negative. Stride is added to the square bracket as a **second colon `:`**, the stride form will be `[start_index : end_index : step]`. Step control defines how many elements to skip before selecting next element.&#x20;

{% tabs %}
{% tab title="Code" %}

```python
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

my_list[1:7:2] # this will select elements 2nd to 7th every two steps
```

{% endtab %}

{% tab title="Output" %}

```python
[3, 5, 7]
```

{% endtab %}
{% endtabs %}

### List reverse

Python lets you to easily reverse lists

{% tabs %}
{% tab title="Code" %}

```python
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

my_list[::-1]
```

{% endtab %}

{% tab title="Output" %}

```python
[0, 9, 2, 6, 5, 1, 8, 7, 5, 5, 4, 3, 2]
```

{% endtab %}
{% endtabs %}

## Lists can be nested

A list can contain sublists, which in turn can contain sublists themselves.&#x20;

![A list of lists with their indice](https://2210269271-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M2JwSQyF92eIZDOl88R%2F-M2m0Ooa9n6pzxFQkTVq%2F-M2m0eQDwB6Kf-aiHXfb%2Fimage.png?alt=media\&token=5110e577-866b-4170-bb03-bb8280aee1d8)

Each element in list or its sublists can be accessed with element index.

{% tabs %}
{% tab title="Code" %}

```python
my_list = ['a', ['b', 'c', 'd'], 'e', [['f', 'g'], 'h'], 'i', 'j']

my_list[3]
```

{% endtab %}

{% tab title="Output" %}

```python
# Returns all sublists in the index number 3
[['f', 'g'], 'h']
```

{% endtab %}
{% endtabs %}

Each sublist adds another square bracket to access its elements. `my_list[3][1]` returns index 3 of main list and an element at index 1 of the sublist

Simply append another square bracket. All operation of slicing can also be performed on the second square bracket, etc.

{% tabs %}
{% tab title="Code" %}

```python
my_list = ['a', ['b', 'c', 'd'], 'e', [['f', 'g'], 'h'], 'i', 'j']

my_list[3][1]
```

{% endtab %}

{% tab title="Output" %}

```python
# It return index 3 of main list and elements at index 1 of the sublist
'h'
```

{% endtab %}
{% endtabs %}

## Lists are mutable

Elements with a list can be deleted, shifted, updated or modified after the list has been created. You can change each element of a list or append new elements to a list.&#x20;

You can use assignment operator (`=`) to change an item or a range of items.

### **Updating a single element**

A single value in a list can be replaced by indexing and assignment operator.

{% tabs %}
{% tab title="Code Index" %}

```python
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

my_list[5] = 2020
```

{% endtab %}

{% tab title="Output 1" %}

```python
[2, 3, 4, 5, 5, 2020, 8, 1, 5, 6, 2, 9, 0]
```

{% endtab %}

{% tab title="Code Negative Index" %}

```python
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

my_list[-3] = 2020
```

{% endtab %}

{% tab title="Output 2" %}

```python
[2, 3, 4, 5, 5, 7, 8, 1, 5, 6, 2020, 9, 0]
```

{% endtab %}
{% endtabs %}

### Updating multiple elements

Multiple elements can be update by specifying the elements index

{% tabs %}
{% tab title="Code" %}

```python
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

my_list[5:8] = [2018, 2019, 2020] 
```

{% endtab %}

{% tab title="Output" %}

```python
[2, 3, 4, 5, 5, 2018, 2019, 2020, 5, 6, 2, 9, 0]
```

{% endtab %}
{% endtabs %}

### **Deleting a single element**

An element or elements can be deleted using `del` keyword.

{% tabs %}
{% tab title="Code: Delete an element" %}

```python
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

del my_list[5]
```

{% endtab %}

{% tab title="Output 1" %}

```python
[2, 3, 4, 5, 5, 8, 1, 5, 6, 2, 9, 0]
```

{% endtab %}

{% tab title="Code: Delete elements" %}

```python
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

del my_list[3:6]
```

{% endtab %}

{% tab title="Output 2" %}

```python
[2, 3, 4, 8, 1, 5, 6, 2, 9, 0]
```

{% endtab %}
{% endtabs %}

First example deletes element `[7]`, second example deletes three elements `[5, 5, 7]`.

### **Prepending or appending elements to a list**&#x20;

An element or elements can be added to the start or end of a list using the `+` operator. This is also called **concatenation**.

{% tabs %}
{% tab title="Prepend" %}

```python
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

[343, 564] + my_list

# OUTPUT
[343, 564, 2, 3, 4, 5, 5, 7, 8, 1, 5, 6, 2, 9, 0]
```

{% endtab %}

{% tab title="Append" %}

```python
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

my_list + [343, 564]

# OUTPUT
[2, 3, 4, 5, 5, 7, 8, 1, 5, 6, 2, 9, 0, 343, 564]
```

{% endtab %}
{% endtabs %}

If you want to add a single element, we have to wrap it in square brackets `[]`. Otherwise, Python raises a `TypeError`.

{% tabs %}
{% tab title="Code" %}

```python
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

my_list = 22 + my_list
```

{% endtab %}

{% tab title="Output" %}

```python
TypeError       Traceback (most recent call last)
<ipython-input-11-57d83415c5aa> in <module>()
      1 my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]
      2 
----> 3 my_list = 22 + my_list

TypeError: unsupported operand type(s) for +: 'int' and 'list'
```

{% endtab %}
{% endtabs %}

The `=` assignment operator can be used to save the prepending or appending elements.&#x20;

{% tabs %}
{% tab title="Prepend" %}

```python
# Elements addition
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

my_list = [343, 564] + my_list

print(my_list)

#OUTPUT
[343, 564, 2, 3, 4, 5, 5, 7, 8, 1, 5, 6, 2, 9, 0]
```

{% endtab %}

{% tab title="Append" %}

```python
# Elements addition
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

my_list = my_list + [343, 564]

print(my_list)

#OUTPUT
[2, 3, 4, 5, 5, 7, 8, 1, 5, 6, 2, 9, 0, 343, 564]
```

{% endtab %}
{% endtabs %}

The `+=` augmented assignment operator works only when we append elements to a list&#x20;

{% tabs %}
{% tab title="Prepend" %}

```python
# Elements addition
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

[343, 564] += my_list

#OUTPUT
  File "<ipython-input-9-3ec7d1771475>", line 3
    [343, 564] += my_list
                         ^
SyntaxError: can't assign to literal
```

{% endtab %}

{% tab title="Append" %}

```python
# Elements addition
my_list = [2, 3, 4, 5, 5, 7, 8, 1,5, 6, 2, 9, 0]

my_list += [343, 564]

print(my_list)

#OUTPUT
[2, 3, 4, 5, 5, 7, 8, 1, 5, 6, 2, 9, 0, 343, 564]
```

{% endtab %}
{% endtabs %}

The `*` operator repeats a list for a given number of times.

{% tabs %}
{% tab title="Code" %}

```python
my_cities = ['Krakow', 'Warsaw', 'Lodz', 'Kielce']

my_cities * 3
```

{% endtab %}

{% tab title="Ouput" %}

```python
['Krakow', 'Warsaw', 'Lodz', 'Kielce', 
 'Krakow', 'Warsaw', 'Lodz', 'Kielce', 
 'Krakow', 'Warsaw', 'Lodz', 'Kielce']
```

{% endtab %}
{% endtabs %}

## List methods

list methods modify the target list in place. They do not return a new list. We do not need to use assignment operators such as `=`.

### `append()`

You can use `append()` to added an element to the end of a list.&#x20;

{% tabs %}
{% tab title="First Tab" %}

```python
age = [23, 45, 89, 18, 24, 29, 36]

age.append(57)
```

{% endtab %}

{% tab title="Output" %}

```python
[23, 45, 89, 18, 24, 29, 36, 57]
```

{% endtab %}
{% endtabs %}

A list can be added to another list, but it will append the list as a sublist rather than extending the elements within the main list (it is added as a single object).

{% tabs %}
{% tab title="Code" %}

```python
age = [23, 45, 89, 18, 24, 29, 36]

age.append([57, 34, 19])
```

{% endtab %}

{% tab title="Output" %}

```python
[23, 45, 89, 18, 24, 29, 36, [57, 34, 19]]
```

{% endtab %}
{% endtabs %}

### `extend()`

Similar to `append()`, `extend()` also adds element/s to the end of a list and only modifies the original list. the argument between `()` should be an iterable, i.e., adding an element at a time.

{% tabs %}
{% tab title="Code" %}

```python
age = [23, 45, 89, 18, 24, 29, 36]

age.extend([57, 34, 19])
```

{% endtab %}

{% tab title="Output" %}

```python
[23, 45, 89, 18, 24, 29, 36, 57, 34, 19]
```

{% endtab %}
{% endtabs %}

You can see the difference between `append()` and `extend()` methods when adding a list to a list. `append()` adds as a sublist but `extend()` adds an element at a time

### `insert()`

You can insert one element at a desired location by using the method `insert()`. insert() takes two arguments:&#x20;

1. The index location to add the element and&#x20;
2. the element (string, float, integer etc).

The newly inserted element will push the elements from the index insert location to the right.

{% tabs %}
{% tab title="Code" %}

```python
['Krakow', 'Warsaw', 'Lodz', 'Kielce']
my_cities.insert(2, 'Poznan')
```

{% endtab %}

{% tab title="Output" %}

```python
['Krakow', 'Warsaw', 'Poznan', 'Lodz', 'Kielce']
```

{% endtab %}
{% endtabs %}

### `pop()`&#x20;

The `pop()` **removes** and **returns** the last element when no index is provided. You can use `pop()` with an index to remove element at the given index. `pop()` is helpful because it may insert or remove an element from only one end, as a result, lists can be implemented as stacks (last-in, first-out).

{% tabs %}
{% tab title="Code" %}

```python
my_cities = ['Krakow', 'Warsaw', 'Warsaw', 'Lodz', 'Kielce']

# pop() returns last element
my_cities.pop()

# Above list misses last element
print(my_cities)
```

{% endtab %}

{% tab title="Output" %}

```python
# Output for pop()
'Kielce'

# Our list after applying pop()
['Krakow', 'Warsaw', 'Warsaw', 'Lodz']
```

{% endtab %}
{% endtabs %}

### `remove()`

You can use `remove()` method to remove a given element. You have to provide the element (not its index).

{% tabs %}
{% tab title="Code" %}

```python
my_cities = ['Krakow', 'Warsaw', 'Lodz', 'Kielce']

my_cities.remove('Krakow')
```

{% endtab %}

{% tab title="Output" %}

```python
['Warsaw', 'Lodz', 'Kielce']
```

{% endtab %}
{% endtabs %}

`remove()` removes only the **FIRST** occurrence of the element.

{% tabs %}
{% tab title="Code" %}

```python
my_cities = ['Krakow', 'Warsaw', 'Warsaw', 'Lodz', 'Kielce']

my_cities.remove('Warsaw')
```

{% endtab %}

{% tab title="Output" %}

```python
['Krakow', 'Warsaw', 'Lodz', 'Kielce']
```

{% endtab %}
{% endtabs %}

You can check the Jupyter Notebook in GitHub or Colab.
