- [Narrator] Python makes it really easy
when you have a sequence of values
to obtain a subset of that sequence;
what's known as a slice operation.
In this video and the next,
we're going to talk about various slicing techniques.
Here, we'll focus on slicing techniques
for copying subsets of sequences
and those techniques will work the same way
whether you're talking about lists,
tuples, or strings.
When you take a subset of a list,
you'll get a list,
when you take a subset of a string,
you'll get a string,
and when you take a subset of a tuple,
you'll get a tuple.
Now, you can also use slices to modify mutable sequences,
such as lists,
and we'll demonstrate those techniques in the next video.
So for the purpose of this discussion,
we're going to work with a list called
numbers containing the integers that you see here,
and the data type stored within the list
is somewhat irrelevant for this discussion.
We happen to be using integers,
but of course, you could have a list of anything you want,
and these slicing operations that I'm about to show you
will work for all of those scenarios.
Now, in the list numbers,
let's demonstrate the most basic kind of a slice,
which is where you specify the
starting index of the slice,
and the one past the end index of the slice.
Let's show you what I mean.
So we're going to create a slice expression
where we want to select elements from numbers
starting from index position 2,
so zero, one, two.
We're going to start with the value five,
and in this case, we'd like to go up to but not including
the index six.
So up to but not including the index six,
so we've got three, four, five,
and then this would be the index six.
So we're basically saying that we want
to select these highlighted four elements
from the original list,
and the result of this expression will be a new list
containing copies of the references in the
element positions two through five.
So that's an interesting point,
because that means the new list that I get back
is actually a copy of these references,
and, therefore, both the new sub-list
and the original list refer to the same objects
five, seven, eleven, and thirteen.
This is the result of the expression that
we just typed there,
and, as you can see, again starting from index two,
we go three, four, five,
this is the last element of the subset or the slice,
and then this is the index that we stopped counting at.
So you can see we get the four elements up to
but not including position six
in that subset or that slice.
Now, interestingly, when you're defining slices,
you don't always have to put numbers on both sides
of that colon operation.
So, for example, consider this expression numbers colon six,
in which we imply that we want to
start from the beginning of the list,
and take the subset up to but not including
index position six.
So, implicitly, Python will insert a zero before that colon,
which is the first index in the list
and I will get everything up to but not including
index position six.
So, this expression that we just typed here
is equivalent to saying zero colon six,
so if you know that you always
wanna start from the beginning,
you can leave out the starting index number,
and simply provide a colon and the ending index number,
and you see we get the exact same result.
Now, in a similar fashion,
we can also say go all the way to the end of the list.
So, if we say six colon,
that says start from index position six
and go to the end of the list,
and it will implicitly insert the length of the list
for you in that case.
So, you can see here we get just 17 and 19,
and that last expression is the equivalent
of me going ahead and putting in
the length of the numbers list as the second
index value in that slice expression.
So if I go ahead and do that,
you see we get the exact same results once again.
Now, it turns out that if you ever need to make
a quick copy of a list,
you can use a slicing operation for that
by simply leaving out the indices altogether
and putting a colon inside the square brackets.
In this case, the interpreter is automatically
going to infer zero as the starting index
and the length of the list as the ending index,
and you can see we get a duplicate of the original list.
Now, it's important to note that that is what we call
a shallow copy.
Every slice operation is a shallow copy.
And what that means is we get new data structure objects,
in this case, new lists, from the slice operations,
but we don't get copies of the actual values in memory.
So, there's still only one object with the value two,
one object with the value three,
one object with the value five, et cetera,
and this new list that was just created
refers to the same object containing two
as the original list,
the same object containing three as the original list,
the same object containing five as the original list,
et cetera.
So, it's a shallow copy operation,
and in later lessons,
specifically when we get to the NumPy lesson,
we'll talk about deep copying,
where copies of the actual values get made as well.
Now, as you might expect
from the range function descriptions or discussions
in earlier lessons,
there is also the ability to do slicing with step values,
so you don't always have to select
consecutive elements within your slice.
So, for instance,
if I go ahead and write an expression
like numbers colon colon two,
the first index will be inferred to be zero,
the second index will be inferred to be
the length of the list numbers,
and the third index to the right of the second colon
is the step.
So, what we're saying here is starting from the
beginning of this list,
going all the way through the end of the list,
we want to select every second element.
So, we'll select the element at position zero,
position two, position four, et cetera.
And you can see we get two, five, eleven, and seventeen
as a result of that particular slicing operation.
And, taking that a step further,
no pun intended,
we can count backwards as well.
So, we can say numbers sub colon colon minus one,
and what this says is give me a copy of the entire list
in reverse order.
So, we're basically counting backwards one step at a time.
Now, it's inferring based on the negative step
that we want to start from the end of the list
and work our way backwards,
so you can see that this is a super quick way
to get a reversed list from the original list.
Now, this particular one,
the indices that we're getting as the defaults are
a little bit different from what you might expect.
So, this is actually the equivalent of saying
start from the last element using negative indices
and go backwards
up to but not including nine prior elements.
There's only eight elements in the list.
So this second value, remember, is always up to
but not including that position,
and then we're going to count backwards
one element at a time.
So this is the equivalent, and obviously
that's a little bit hard to figure out,
so this nice, concise notation up above
is the typical way in which you would reverse a list
using a slicing operation.
In the next video, we'll start talking about the slice
operations that can modify a list.