- [Instructor] In this video, we're going to start
filling in a lot of the missing pieces
about the list data structure in Python.
Now, most commonly, lists are used
to store homogeneous data.
That means all data of the same type.
So for example, here we're creating a list called c,
and we've got a bunch of whole number values,
all of those are considered to be integers in Python.
Now there's no requirement in Python
that all of the elements must be of the same type,
so it is okay to store heterogeneous data
in a list if you'd like.
So for instance, I could have a combination of strings
and integers and floating point numbers
and any other type that you might
be able to think of as well.
Now of course, once we define a list,
which again is done with a set of square brackets in Python
we can evaluate that list to see
what its contents look like
in a string-based representation.
So this is the output format for a list
that's built into Python itself.
Now one of the new things that we want to take a look at
in this video is accessing individual
list elements directly.
So first I just want to show a diagram
of the list that we just created.
As in most C-based programming languages,
indexing or accessing of the individual elements
within a list is done from index number zero.
So the value 45, or minus 45, excuse me,
is at index position zero within the list c,
and this is the actual syntax that you would use
to name the location in memory where minus 45 is stored
so that you can get that value and use it,
or so that you can assign a new value to that element
of the list if you would like.
So you can see here, the names of the five elements
of the list that we just created
are c sub zero through c sub four.
So with that said, let's go back over
to our interactive iPython session,
and let's just display the values
of a couple of the elements in our list.
So c sub zero is indeed minus 45,
and c sub four is indeed 1543, the last element of the list.
Now we talked previously about the fact
that lists know their own length.
So let's go ahead and check the length of the list c,
and we can see that indeed it has five elements,
and you can confirm that by counting
the elements back in the original list up above.
I should mention, by the way,
that unlike many C-based programming languages,
Python does not have a data structure called an array
built into the language itself.
List is the closest thing to an array
that we have in Python.
Arrays in most other C-based programming languages
are fixed-length entities,
whereas Python lists are dynamically
resizable and changeable,
so they're a lot more flexible than arrays
in most programming languages.
When we do talk about the concept of arrays in these videos
we'll do so a couple of lessons from now
when we introduce the NumPy Numeric Python library,
which is the most popular library
for manipulating array data structures,
performance-wise, in Python.
And by the way, when we get to that point,
we'll talk about some of the reasons
why numerical Python arrays are more efficient than lists.
We'll even do some timing comparisons
on some similar operations.
Now one of the things that's really interesting
about lists in Python versus arrays
in some other programming languages
is the fact that in addition to positive index numbers,
which by the way must be integer values,
you can also use negative index numbers
to access the elements from the end of a list.
So let's go ahead and take a look at a diagram
that adds in the negative index names
of the elements in our five element list called c.
Now as you can see here, c sub minus one
actually represents the last element of the list.
c sub minus two is the second to last element,
minus three is the third to last element,
all the way down to minus five,
which is actually the first element.
So basically you can figure out the corresponding
positive index by adding the list's length
to the negative indices that you see here.
So if I add five to minus one, I get four,
which is the last element of the list.
If I add five to minus two, I get three.
If I add five to minus three, I get two,
et cetera all the way back to,
if I added five to minus five, I get c sub zero,
which of course is the first element within the list.
So with that said, let's switch back over
to the interactive iPython session here,
and let's try accessing a couple of elements
using negative indices.
So if I say c sub minus one,
that says I want the first element from the end of the list,
and that first element from the end of the list is 1543.
So indeed, we do get 1543 there.
And if I say c sub minus five,
we're saying we want to go backwards
five elements from the end of the list.
So if I go from the end of the list backwards,
one, two, three, four, five,
I'm saying I want actually the first element of the list
in that particular case.
Now, the index values that you use
must be either integer values or integer expressions.
So for example, if I go and I define a variable a
and I give it the value one,
and let's define another variable b
and give the the value two,
I can write an expression like c sub a plus b,
and of course a plus b will be evaluated first
to give me the value three.
And going back and looking at our original list here,
zero, one, two, three,
the element with the value 72 is what we'll be accessing
when we evaluate that expression.
Now I've mentioned a couple of times that lists are mutable
meaning that you can change their contents.
Well, one way to change the contents
is to assign a new value to an existing element.
So for instance, if I write an expression like c sub four
gets the value 17, now when I display
the contents of the list,
I can see that 17 has replaced the old value 1543
in the last element of our list.
So that's one way in which lists are mutable.
We'll talk about dynamically modifying the size of a list
in a few moments as well.
Now some of the sequences that you're going to wind up
manipulating in Python are immutable,
and we've actually already dealt
with two different sequence types
that are immutable in Python, strings and tuples.
So let's talk about a string for just a moment here.
Let's say we create a string, and we give it the value hello
and by the way all sequences can be accessed
element-by-element using similar techniques
to what we've shown you here for lists.
So for example, I can go and say,
give me the character at position zero in that string.
In Python, we don't have a separate character type,
so what we actually get out of this is a string
representing that one character within the string.
So s sub zero is the letter h.
Now, like I said, strings are immutable,
so if you attempt to place a new character
into that position, let's say we wanted to replace
the lowercase h with an uppercase H,
what you're going to get as a result of that
is an exception at runtime here.
So in this case you see a type error.
It's a type error because the string type str
doesn't support assignment
to the elements within the string.
So previously we showed you that a list knows its own length
and that we're able to calculate that length
by passing the list to the built-in function named L-E-N,
len in the Python language.
Now, because lists know their own length,
they do check when you specify an index
to see whether that index is in range, as you might expect.
So let's go ahead and try to access an element
that's not part of our list c,
and you can see that we get an index error in this case
indicating that the list index is out of range.
Of course, each of the elements within the list
is effectively a variable unto itself.
So you can also do things like use
the different list elements in expressions.
So if we do c sub zero plus c sub one
plus, whoops, plus c sub two for example,
that will simply add together
the first three elements of the list.
Now we already demonstrated up above
that lists are modifiable,
and you can actually add new items to a list
a couple of different ways,
one of which is using the plus equals operator
that we've demonstrated previously.
So let's say we have a variable called a_list
and we initialize it with an empty set of square brackets,
which means a list of no elements at least so far.
Because lists are mutable, we can add items to the list,
like I said, using that plus equals operator.
So for example, if we wanted to add the numbers
from one through five to the list,
we could write a for loop, something like this,
where we use the range function,
and remember that range produces values
from the starting value up to
but not including the ending value.
And for each of those, we can go ahead and say
a_list plus equals and number,
and that will now go ahead, I'm sorry.
I typed that wrong.
We can do plus equals with number in square brackets,
which will add a list containing just the number
to the end of the variable a_list.
Now what that does is it concatenates
this one element list that we are currently
putting on the right side of the expression
to the end of the elements currently stored in a_list.
Now this is important, the plus equals operator's
right-hand side must be something that is a sequence
in order for the plus equals operator to work correctly.
So it's a concatenation operator in this context.
So let's go ahead and execute that for loop,
and now we can evaluate a_list
and see that we were able to place the values
one through five into the list.
So let's go back to this issue
of the right-hand side of the plus equals operator.
When the left side of this operator is a list,
the right side must be some sort of iterable object,
typically a sequence like a list or a tuple,
or even a string.
So for example, if I go and create a list called letters,
which is currently empty,
and then I say letters plus equals,
and I give it the string.
Actually, let's say Python here instead of hello,
since I always do hello.
So letters plus equals Python.
Now, what you might think is going to happen here, sorry,
is that the string object Python
will be placed into that list.
But in reality, what happens is each individual letter
gets placed into the list.
So now we have a list of strings
where each string is one letter from the sequence
that was on the right side of that plus equals operator.
Now you might expect that if you can do plus equals,
you can also do plus, and indeed you can.
So the plus operator acts as a concatenation operator
in the context of lists.
So let's say we have a list with 10, 20, and 30,
and let's say we have another list,
and we'll make this one 40 and 50, just for argument's sake.
Now if I go and create a concatenated list.
Actually, let's call it that, concatenated_list.
So we can say list1 plus list2.
And if we then go and evaluate that,
you can see that indeed the new list that was created
contains all of the existing items.
Now, because of the fact that we used the plus operator,
neither list1 nor list2 got modified by snippet 26 here.
If you're using the plus equals operator,
as we did way back up here,
we saw that that really did modify the empty list
to add elements to the list.
Now we can also use the for statement,
along with the range function to access elements,
(clears throat) excuse me, of a list,
via their index numbers.
So for instance, if I go ahead and write a for loop
of this format, so we'll, for i in range,
and then we use the len function to say,
give us the length of the concatenated list.
So let's talk about that before I continue.
We already know that the len function
is able to give us back the number of items in a list.
The list we're talking about is concatenated_list,
which has five elements, so the result
of this expression is five.
So for i in range five is really saying,
give me the integer value zero through four,
which are the indices of the list right up above
that we just created.
So now that we have that,
we can go and do something like a print statement.
Let's use a format string in this case.
And we'll display the index number,
followed by a colon, and in a second placeholder,
let's go ahead and show the concatenated_list element
at position i within that list.
So close off our string and close the parenthesis.
So now you can see the indices of the values,
and the actual value at each index.
So that's the same old indexed access
that we did several times up above.
One other thing I want to show you in this video
with respect to lists is that, for convenience,
you're able to compare the elements of multiple lists
using the comparison operators
that we showed you previously.
So for example, if I go ahead and create a list,
let's say, that has one, two, and three in it,
and let's create a second list
that also has one, two, and three in it.
Woops, that's one, two, and three.
And let's create a third list this time
that has an extra element in it, one, two, three, four.
Alright, so we have a few lists that we can work with.
And let's say we want to know whether
a couple of these lists are equal to one another or not.
So for instance, if I do a double equals b,
I'm comparing the list object that a refers to,
with the list object that b refers to.
The contents of these two lists are identical,
and therefore, we get true as a result.
Now, the list a is a subset of the list c,
so they're not equal 'cause they don't have
the same number of elements,
and they don't have the same exact contents
within the lists themselves.
So in this case, you can see that we get false.
Now interestingly, you can also use the less than,
less than or equal, greater than,
and greater than or equal operators also.
So for instance, if I say a less than c,
this is going to be true, because a is a subset of c.
So indeed, we get true in that case.
And, let's talk about c and b for a moment.
c and b have some shared elements,
just like a and c had shared elements.
Let's do an expression like c greater than or equal to b.
While c contains everything that b does and more,
so as you can see, we get true
as a result of that expression.
So in this video we saw a whole bunch
of different operations that you can perform on lists
here in the context of Python.