# Python Lists: A Complete Guide

Python lists are a fundamental data type in Python. [They are similar to Arrays in other languages, such as Javascript](https://fjolt.com/article/javascript-arrays-introduction). You can learn more about the main [Python data structures here](https://fjolt.com/article/python-data-collections).

To create a list in Python is super easy. Let's start with some of the basics, and then dive into useful ways you'll be able to work with lists. To start a new list, simply [define a variable in Python](https://fjolt.com/article/python-variables), with the contents encapsulated in `[]` square brackets:

```python
myList = [ "some", "list", "contents" ]
```

As Python is a language that is dynamically typed, there are no major limitations on what can go inside a list, so feel free to add other types such as integers or floats too:
```python
myList = [ "some", "list", "contents", 1, 2.5, "etc" ]
```

Empty lists can be defined as `[]` empty square brackets should you need to do that too:
```python
myList = []
```

**Lists** can also be **nested**, or contain lists within lists (... within lists). So this is also valid python:
```python
myList = [ [ "some", "list" ], "inside", "a", "list" ]
```

Getting the length of a list is done using the standalone `len()` function. Here's an example where we try to get the length of our nested list:
 ```python
myList = [ [ "some", "list" ], "inside", "a", "list" ]
print(len(myList)) # returns 4
```

Finally, we can reference items in a list using the square bracket notation. For example, to get the first item of a list:
```python
myList = [ "some", "list", "contents", 1, 2.5, "etc" ]
print(myList[0]) # "some"
```

Or, to get the first two items:
```python
myList = [ "some", "list", "contents", 1, 2.5, "etc" ]
print(myList[0:2]) # [ "some", "list" ]
```

## List Methods in Python
**Lists** come with a bunch of built in methods in Python, to allow us to fully realise their potential as data stores. These methods are:
- `list.append("newItem")` - appends an item with the value `newItem` to the end of the lists.
- `list.extend(["newItem"])` - appends another iterable item onto the list, for example - combining two lists.
- `list.insert(0, "newItem")` - inserts a list item `newItem` and index 0. You can change the value of the index, to decide where the item should be inserted.
- `list.clear()` - deletes the lists contents entirely.
- `list.remove("someItem")` - removes the first item of the list with a value of `item`. Will throw an error if no value `item` exists.
- `list.count("someItem")` - counts any instances of `someItem` in the list. If no item in the list has the value `someItem` then it will return 0.
- `list.copy()` - creates a shallow copy of the list.
- `list.reverse()` - reverse the elements of the list.
-  `list.pop(10)` - removes an item at position 10 of the list, and returns it. If you don't define a number, it'll remove the last item, i.e. `list.pop()`.
- `list.sort()` - for sorting lists.


To bring this to life, let's look at a few examples of how it works in practice:

### Appending and Inserting new list items
One of the most common things you'll want to do with a list is adding new data to it. If we've created a list, we can append data using the `append` method as mentioned, or `insert` to insert items at a certain position:

```python
myList = [ "inside", "a", "list" ]
myList.append("friend")
myList.insert(2, "new")
print(myList); # ['inside', 'a', 'new', 'list', 'friend']
```

You can also add to a list using `+=`:
```python
myList = [ "inside", "a", "list" ]
myList += "friend"
print(myList) # ['inside', 'a', 'list', 'friend']
```

Or, if you have two lists, you can add the second onto the first using `extend`:
```python
myList = [ "some", "list" ]
otherList = [ "other", "list" ]

myList.extend(otherList)
print(myList) # ['some', 'list', 'other', 'list']
```

### Deleting lists and lists content
An equally common thing you'll want to do, once you add everything to your list, is to delete items. You can delete with `remove` or `clear` to simply delete the entire list:
```python
myList = [ "inside", "a", "list" ]
myList.remove("inside")
print(myList) # ['a', 'new']


myList.clear()
print(myList) # returns []
```

### Reversing a List in Python
You'll also want to reverse lists, in some situations. Python has a build in method for this, so no need to define your own:
```python
myList =  [ "inside", "a", "list" ]
myList.reverse()
print(myList) # ['list', 'a', 'inside']
```

### Making copies of lists 
In Python, we use `==` to compare by value, and `is` to compare by reference. We can use `copy()` to make a new reference for a list. This will make a new reference point in memory pointing to the same value. Below, `myList` and `otherList` are equal in value, but now their reference is different, so `myList is otherList` returns false:
```python
myList =  [ "a", "list" ]
otherList = myList.copy()
print(myList == otherList) # True
print(myList is otherList) # False
```

This can also be written as `myList[:]`, if you want to avoid using the `copy()` method:
```python
myList =  [ "a", "list" ]
otherList = myList[:]
print(myList == otherList) # True
print(myList is otherList) # False
```


### Sorting Lists in Python
Sorting a list in ascending order is easy using the `sort` function, and all items are of the same type:
```python
myList =  [ "a", "c", "e", "b", "f", "d", "g", "z", "w", "x" ]
myNumberList = [ 1, 3, 5, 2, 7, 4, 6 ]

myList.sort()
myNumberList.sort() 

print(myList) # ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'w', 'x', 'z']
print(myNumberList) # [1, 2, 3, 4, 5, 6, 7]
```

If you try to sort where the list contains different types - like integers and strings, you'll end up getting an error. If you want to sort a list based on another feature of the list, you can define its `key`, and `reverse` arguments:
- `key` gives us a number which will be used to compare the list content
- `reverse` if set to true will reverse the order.

For example, to put all values which are `a` at the start, we could try something like this:
```python
def isA(letter):
    if(letter == "a"):
        return 1
    else:
        return 0

myList =  [ "a", "c", "a", 5, "f", "a", 2, "z", "a", "x" ]

myList.sort(key=isA, reverse=True)

print(myList) # ['a', 'a', 'a', 'a', 'c', 5, 'f', 2, 'z', 'x']
```

Here, we define a function `isA`, which takes each item in the list as its first argument (`letter`). If the letter is `a`, then it returns 1, otherwise it returns 0. Then we reverse the list using the `reverse=True` argument, to get all the `a`s at the start.

### Lists function best as stacks of data!
Since lists are **ordered**, they function best as stacks, which means adding and removing items from the end of a list is super fast, while adding or removing items from the start is kind of slow. That means it's recommended to use `pop` and `append` where possible, as this is going to be a lot faster on large data sets than other methods on lists.

## Conclusion

Lists are super powerful data structures in Python, and used **everywhere**. You can learn more about Python data structures here. To learn more about other engineering topics, [check out the rest of my content](https://fjolt.com). You can read more about Python data structures below:
- [Python Data Collections](https://fjolt.com/article/python-data-collections)
- **Python Data Collections: Lists**
- [Python Data Collections: Tuples](https://fjolt.com/article/python-tuples)
- [Python Data Collections: Sets](https://fjolt.com/article/python-sets)
- [Python Data Collections: Dictionaries](https://fjolt.com/article/python-dictionaries)

