Confusion about Python list slice results - python

I'm new to Python, the following output I'm getting from a simple list slice operation confused the jebuse out of me.
Here is the code.
>>> a = [1,2,3,4];
>>> a[1:3]
[2, 3]
>>> a[3]
4
shouldn't a[1:3] returns [2,3,4] instead of [2,3]?

a[1:3] specifies a half-closed interval, which means it includes the values starting at the 1st specified index up to, but not including, at the 2nd index.
So in this case a[1:3] means the slice includes a[1] and a[2], but not a[3]
You see the same in the use of the range() function. For instance
range(1, 5)
will generate a list from 1 to 4, but will not include 5.
This is pretty consistent with how things are done in many programming languages.

Slicing returns up to (but not including) the second slice index.

The docs for slice may help.
slice([start], stop[, step])
Return a slice object representing the
set of indices specified by range(start, stop, step).
The slice format that most of are familiar with is just a shorthand:
a[start:stop:step]

You've got some good answers about how it works, here's one with why:
a = '0123456789'
a[2:4]
'23'
a[4:6]
'45'
a[6:8]
'67'
IOW, it makes it easy to step through a list or string or tuple n characters at a time, without wasting time on the +1 / -1 stuff needed in most languages.

Related

What's the difference between list.append(a) vs. list = list + [i] (for the purposes of recursion)? [duplicate]

Why do these two operations (append() resp. +) give different results?
>>> c = [1, 2, 3]
>>> c
[1, 2, 3]
>>> c += c
>>> c
[1, 2, 3, 1, 2, 3]
>>> c = [1, 2, 3]
>>> c.append(c)
>>> c
[1, 2, 3, [...]]
>>>
In the last case there's actually an infinite recursion. c[-1] and c are the same. Why is it different with the + operation?
To explain "why":
The + operation adds the array elements to the original array. The array.append operation inserts the array (or any object) into the end of the original array, which results in a reference to self in that spot (hence the infinite recursion in your case with lists, though with arrays, you'd receive a type error).
The difference here is that the + operation acts specific when you add an array (it's overloaded like others, see this chapter on sequences) by concatenating the element. The append-method however does literally what you ask: append the object on the right-hand side that you give it (the array or any other object), instead of taking its elements.
An alternative
Use extend() if you want to use a function that acts similar to the + operator (as others have shown here as well). It's not wise to do the opposite: to try to mimic append with the + operator for lists (see my earlier link on why). More on lists below:
Lists
[edit] Several commenters have suggested that the question is about lists and not about arrays. The question has changed, though I should've included this earlier.
Most of the above about arrays also applies to lists:
The + operator concatenates two lists together. The operator will return a new list object.
List.append does not append one list with another, but appends a single object (which here is a list) at the end of your current list. Adding c to itself, therefore, leads to infinite recursion.
As with arrays, you can use List.extend to add extend a list with another list (or iterable). This will change your current list in situ, as opposed to +, which returns a new list.
Little history
For fun, a little history: the birth of the array module in Python in February 1993. it might surprise you, but arrays were added way after sequences and lists came into existence.
The concatenation operator + is a binary infix operator which, when applied to lists, returns a new list containing all the elements of each of its two operands. The list.append() method is a mutator on list which appends its single object argument (in your specific example the list c) to the subject list. In your example this results in c appending a reference to itself (hence the infinite recursion).
An alternative to '+' concatenation
The list.extend() method is also a mutator method which concatenates its sequence argument with the subject list. Specifically, it appends each of the elements of sequence in iteration order.
An aside
Being an operator, + returns the result of the expression as a new value. Being a non-chaining mutator method, list.extend() modifies the subject list in-place and returns nothing.
Arrays
I've added this due to the potential confusion which the Abel's answer above may cause by mixing the discussion of lists, sequences and arrays.
Arrays were added to Python after sequences and lists, as a more efficient way of storing arrays of integral data types. Do not confuse arrays with lists. They are not the same.
From the array docs:
Arrays are sequence types and behave very much like lists, except that the type of objects stored in them is constrained. The type is specified at object creation time by using a type code, which is a single character.
append is appending an element to a list. if you want to extend the list with the new list you need to use extend.
>>> c = [1, 2, 3]
>>> c.extend(c)
>>> c
[1, 2, 3, 1, 2, 3]
Python lists are heterogeneous that is the elements in the same list can be any type of object. The expression: c.append(c) appends the object c what ever it may be to the list. In the case it makes the list itself a member of the list.
The expression c += c adds two lists together and assigns the result to the variable c. The overloaded + operator is defined on lists to create a new list whose contents are the elements in the first list and the elements in the second list.
So these are really just different expressions used to do different things by design.
The method you're looking for is extend(). From the Python documentation:
list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
list.extend(L)
Extend the list by appending all the items in the given list; equivalent to a[len(a):] = L.
list.insert(i, x)
Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x).
you should use extend()
>>> c=[1,2,3]
>>> c.extend(c)
>>> c
[1, 2, 3, 1, 2, 3]
other info: append vs. extend
See the documentation:
list.append(x)
Add an item to the end of the list; equivalent to a[len(a):] = [x].
list.extend(L)
- Extend the list by appending all the items in the given list;
equivalent to a[len(a):] = L.
c.append(c) "appends" c to itself as an element. Since a list is a reference type, this creates a recursive data structure.
c += c is equivalent to extend(c), which appends the elements of c to c.

choosing a random number from a tuple + some numbers

I have a tuple of numbers, and I want to choose a random number from my tuple in addition with a certain number. For example:
my_tuple = (1,2,3)
and I have the number 4. I want to choose a random number from the numbers 1,2,3,4 (without changing the tuple of course).
I tried:
my_tp = (1, 2, 3)
a = random.choice(list(my_tp).append(4))
print(a)
I'm new to python. I tried converting the tuple to a list, and then performing the random function.
The code above didn't work. Got the error
object of type 'NoneType' has no len()
Would love some help.
list.append returns none
Once converting to a list as you have done, appending will modify that list but return none so that is the source of your error.
To get round that you can either convert the tuple to a list then append 4 to it, then use random.choice, or in just one step, you can concatenate a list of [4] with the + operand.
This approach is much simpler:
import random
my_tuple = (1,2,3)
random.choice(list(my_tuple) + [4])
Hope this helps and clears some things up! :)
Update:
If you want to just randomly select from the tuple without the last item, then just slice the list with the normal syntax:
random.choice(list(my_tuple)[:-1])
The method list.append alters the provided list and returns None, which explains the exception you got. To get the desired result, you can implicitly use the tuple.__add__ method, which will return a new tuple.
values = (1, 2, 3)
random.choice(values + (4,))
If you want to remove values in a concise-ish fashion, using a set might be appropriate.
values = {1, 2, 3}
random.choice(list(values - {3}))
You can try:
my_tuple = (1,2,3)
random.choice((*my_tuple, 4))
Where (*my_tuple, 4) creates a new tuple with the unpacked content of my_tuple and 4.

How to get the first 2 letters of a string in Python?

Let's say I have a string
str1 = "TN 81 NZ 0025"
two = first2(str1)
print(two) # -> TN
How do I get the first two letters of this string? I need the first2 function for this.
It is as simple as string[:2]. A function can be easily written to do it, if you need.
Even this, is as simple as
def first2(s):
return s[:2]
In general, you can get the characters of a string from i until j with string[i:j].
string[:2] is shorthand for string[0:2]. This works for lists as well.
Learn about Python's slice notation at the official tutorial
t = "your string"
Play with the first N characters of a string with
def firstN(s, n=2):
return s[:n]
which is by default equivalent to
t[:2]
Heres what the simple function would look like:
def firstTwo(string):
return string[:2]
In python strings are list of characters, but they are not explicitly list type, just list-like (i.e. it can be treated like a list). More formally, they're known as sequence (see http://docs.python.org/2/library/stdtypes.html#sequence-types-str-unicode-list-tuple-bytearray-buffer-xrange):
>>> a = 'foo bar'
>>> isinstance(a, list)
False
>>> isinstance(a, str)
True
Since strings are sequence, you can use slicing to access parts of the list, denoted by list[start_index:end_index] see Explain Python's slice notation . For example:
>>> a = [1,2,3,4]
>>> a[0]
1 # first element, NOT a sequence.
>>> a[0:1]
[1] # a slice from first to second, a list, i.e. a sequence.
>>> a[0:2]
[1, 2]
>>> a[:2]
[1, 2]
>>> x = "foo bar"
>>> x[0:2]
'fo'
>>> x[:2]
'fo'
When undefined, the slice notation takes the starting position as the 0, and end position as len(sequence).
In the olden C days, it's an array of characters, the whole issue of dynamic vs static list sounds like legend now, see Python List vs. Array - when to use?
All previous examples will raise an exception in case your string is not long enough.
Another approach is to use
'yourstring'.ljust(100)[:100].strip().
This will give you first 100 chars.
You might get a shorter string in case your string last chars are spaces.
For completeness: Instead of using def you could give a name to a lambda function:
first2 = lambda s: s[:2]

Slicing a list using a variable, in Python

Given a list
a = range(10)
You can slice it using statements such as
a[1]
a[2:4]
However, I want to do this based on a variable set elsewhere in the code. I can easily do this for the first one
i = 1
a[i]
But how do I do this for the other one? I've tried indexing with a list:
i = [2, 3, 4]
a[i]
But that doesn't work. I've also tried using a string:
i = "2:4"
a[i]
But that doesn't work either.
Is this possible?
that's what slice() is for:
a = range(10)
s = slice(2,4)
print a[s]
That's the same as using a[2:4].
Why does it have to be a single variable? Just use two variables:
i, j = 2, 4
a[i:j]
If it really needs to be a single variable you could use a tuple.
With the assignments below you are still using the same type of slicing operations you show, but now with variables for the values.
a = range(10)
i = 2
j = 4
then
print a[i:j]
[2, 3]
>>> a=range(10)
>>> i=[2,3,4]
>>> a[i[0]:i[-1]]
range(2, 4)
>>> list(a[i[0]:i[-1]])
[2, 3]
I ran across this recently, while looking up how to have the user mimic the usual slice syntax of a:b:c, ::c, etc. via arguments passed on the command line.
The argument is read as a string, and I'd rather not split on ':', pass that to slice(), etc. Besides, if the user passes a single integer i, the intended meaning is clearly a[i]. Nevertheless, slice(i) will default to slice(None,i,None), which isn't the desired result.
In any case, the most straightforward solution I could come up with was to read in the string as a variable st say, and then recover the desired list slice as eval(f"a[{st}]").
This uses the eval() builtin and an f-string where st is interpolated inside the braces. It handles precisely the usual colon-separated slicing syntax, since it just plugs in that colon-containing string as-is.

How do I get the last element of a list?

How do I get the last element of a list?
Which way is preferred?
alist[-1]
alist[len(alist) - 1]
some_list[-1] is the shortest and most Pythonic.
In fact, you can do much more with this syntax. The some_list[-n] syntax gets the nth-to-last element. So some_list[-1] gets the last element, some_list[-2] gets the second to last, etc, all the way down to some_list[-len(some_list)], which gives you the first element.
You can also set list elements in this way. For instance:
>>> some_list = [1, 2, 3]
>>> some_list[-1] = 5 # Set the last element
>>> some_list[-2] = 3 # Set the second to last element
>>> some_list
[1, 3, 5]
Note that getting a list item by index will raise an IndexError if the expected item doesn't exist. This means that some_list[-1] will raise an exception if some_list is empty, because an empty list can't have a last element.
If your str() or list() objects might end up being empty as so: astr = '' or alist = [], then you might want to use alist[-1:] instead of alist[-1] for object "sameness".
The significance of this is:
alist = []
alist[-1] # will generate an IndexError exception whereas
alist[-1:] # will return an empty list
astr = ''
astr[-1] # will generate an IndexError exception whereas
astr[-1:] # will return an empty str
Where the distinction being made is that returning an empty list object or empty str object is more "last element"-like then an exception object.
You can also do:
last_elem = alist.pop()
It depends on what you want to do with your list because the pop() method will delete the last element.
The simplest way to display last element in python is
>>> list[-1:] # returns indexed value
[3]
>>> list[-1] # returns value
3
there are many other method to achieve such a goal but these are short and sweet to use.
In Python, how do you get the last element of a list?
To just get the last element,
without modifying the list, and
assuming you know the list has a last element (i.e. it is nonempty)
pass -1 to the subscript notation:
>>> a_list = ['zero', 'one', 'two', 'three']
>>> a_list[-1]
'three'
Explanation
Indexes and slices can take negative integers as arguments.
I have modified an example from the documentation to indicate which item in a sequence each index references, in this case, in the string "Python", -1 references the last element, the character, 'n':
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5
-6 -5 -4 -3 -2 -1
>>> p = 'Python'
>>> p[-1]
'n'
Assignment via iterable unpacking
This method may unnecessarily materialize a second list for the purposes of just getting the last element, but for the sake of completeness (and since it supports any iterable - not just lists):
>>> *head, last = a_list
>>> last
'three'
The variable name, head is bound to the unnecessary newly created list:
>>> head
['zero', 'one', 'two']
If you intend to do nothing with that list, this would be more apropos:
*_, last = a_list
Or, really, if you know it's a list (or at least accepts subscript notation):
last = a_list[-1]
In a function
A commenter said:
I wish Python had a function for first() and last() like Lisp does... it would get rid of a lot of unnecessary lambda functions.
These would be quite simple to define:
def last(a_list):
return a_list[-1]
def first(a_list):
return a_list[0]
Or use operator.itemgetter:
>>> import operator
>>> last = operator.itemgetter(-1)
>>> first = operator.itemgetter(0)
In either case:
>>> last(a_list)
'three'
>>> first(a_list)
'zero'
Special cases
If you're doing something more complicated, you may find it more performant to get the last element in slightly different ways.
If you're new to programming, you should avoid this section, because it couples otherwise semantically different parts of algorithms together. If you change your algorithm in one place, it may have an unintended impact on another line of code.
I try to provide caveats and conditions as completely as I can, but I may have missed something. Please comment if you think I'm leaving a caveat out.
Slicing
A slice of a list returns a new list - so we can slice from -1 to the end if we are going to want the element in a new list:
>>> a_slice = a_list[-1:]
>>> a_slice
['three']
This has the upside of not failing if the list is empty:
>>> empty_list = []
>>> tail = empty_list[-1:]
>>> if tail:
... do_something(tail)
Whereas attempting to access by index raises an IndexError which would need to be handled:
>>> empty_list[-1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: list index out of range
But again, slicing for this purpose should only be done if you need:
a new list created
and the new list to be empty if the prior list was empty.
for loops
As a feature of Python, there is no inner scoping in a for loop.
If you're performing a complete iteration over the list already, the last element will still be referenced by the variable name assigned in the loop:
>>> def do_something(arg): pass
>>> for item in a_list:
... do_something(item)
...
>>> item
'three'
This is not semantically the last thing in the list. This is semantically the last thing that the name, item, was bound to.
>>> def do_something(arg): raise Exception
>>> for item in a_list:
... do_something(item)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 1, in do_something
Exception
>>> item
'zero'
Thus this should only be used to get the last element if you
are already looping, and
you know the loop will finish (not break or exit due to errors), otherwise it will point to the last element referenced by the loop.
Getting and removing it
We can also mutate our original list by removing and returning the last element:
>>> a_list.pop(-1)
'three'
>>> a_list
['zero', 'one', 'two']
But now the original list is modified.
(-1 is actually the default argument, so list.pop can be used without an index argument):
>>> a_list.pop()
'two'
Only do this if
you know the list has elements in it, or are prepared to handle the exception if it is empty, and
you do intend to remove the last element from the list, treating it like a stack.
These are valid use-cases, but not very common.
Saving the rest of the reverse for later:
I don't know why you'd do it, but for completeness, since reversed returns an iterator (which supports the iterator protocol) you can pass its result to next:
>>> next(reversed([1,2,3]))
3
So it's like doing the reverse of this:
>>> next(iter([1,2,3]))
1
But I can't think of a good reason to do this, unless you'll need the rest of the reverse iterator later, which would probably look more like this:
reverse_iterator = reversed([1,2,3])
last_element = next(reverse_iterator)
use_later = list(reverse_iterator)
and now:
>>> use_later
[2, 1]
>>> last_element
3
To prevent IndexError: list index out of range, use this syntax:
mylist = [1, 2, 3, 4]
# With None as default value:
value = mylist and mylist[-1]
# With specified default value (option 1):
value = mylist and mylist[-1] or 'default'
# With specified default value (option 2):
value = mylist[-1] if mylist else 'default'
lst[-1] is the best approach, but with general iterables, consider more_itertools.last:
Code
import more_itertools as mit
mit.last([0, 1, 2, 3])
# 3
mit.last(iter([1, 2, 3]))
# 3
mit.last([], "some default")
# 'some default'
Another method:
some_list.reverse()
some_list[0]
Here is the solution for your query.
a=["first","second","second from last","last"] # A sample list
print(a[0]) #prints the first item in the list because the index of the list always starts from 0.
print(a[1]) #prints second item in list
print(a[-1]) #prints the last item in the list.
print(a[-2]) #prints the second last item in the list.
Output:
>>> first
>>> second
>>> last
>>> second from last
list[-1] will retrieve the last element of the list without changing the list.
list.pop() will retrieve the last element of the list, but it will mutate/change the original list. Usually, mutating the original list is not recommended.
Alternatively, if, for some reason, you're looking for something less pythonic, you could use list[len(list)-1], assuming the list is not empty.
You can also use the code below, if you do not want to get IndexError when the list is empty.
next(reversed(some_list), None)
Ok, but what about common in almost every language way items[len(items) - 1]? This is IMO the easiest way to get last element, because it does not require anything pythonic knowledge.
Strange that nobody posted this yet:
>>> l = [1, 2, 3]
>>> *x, last_elem = l
>>> last_elem
3
>>>
Just unpack.
You can use ~ operator to get the ith element from end (indexed from 0).
lst=[1,3,5,7,9]
print(lst[~0])
Accessing the last element from the list in Python:
1: Access the last element with negative indexing -1
>> data = ['s','t','a','c','k','o','v','e','r','f','l','o','w']
>> data[-1]
'w'
2. Access the last element with pop() method
>> data = ['s','t','a','c','k','o','v','e','r','f','l','o','w']
>> data.pop()
'w'
However, pop method will remove the last element from the list.
METHOD 1:
L = [8, 23, 45, 12, 78]
print(L[len(L)-1])
METHOD 2:
L = [8, 23, 45, 12, 78]
print(L[-1])
METHOD 3:
L = [8, 23, 45, 12, 78]
L.reverse()
print(L[0])
METHOD 4:
L = [8, 23, 45, 12, 78]
print(L[~0])
METHOD 5:
L = [8, 23, 45, 12, 78]
print(L.pop())
All are outputting 78
To avoid "IndexError: list index out of range", you can use this piece of code.
list_values = [12, 112, 443]
def getLastElement(lst):
if len(lst) == 0:
return 0
else:
return lst[-1]
print(getLastElement(list_values))
Pythonic Way
So lets consider that we have a list a = [1,2,3,4], in Python List can be manipulated to give us part of it or a element of it, using the following command one can easily get the last element.
print(a[-1])
You can also use the length to get the last element:
last_elem = arr[len(arr) - 1]
If the list is empty, you'll get an IndexError exception, but you also get that with arr[-1].
If you use negative numbers, it will start giving you elements from last of the list
Example
lst=[1,3,5,7,9]
print(lst[-1])
Result
9
If you do my_list[-1] this returns the last element of the list. Negative sequence indexes represent positions from the end of the array. Negative indexing means beginning from the end, -1 refers to the last item, -2 refers to the second-last item, etc.
You will just need to take the and put [-1] index. For example:
list=[0,1,2]
last_index=list[-1]
print(last_index)
You will get 2 as the output.
You could use it with next and iter with [::-1]:
>>> a = [1, 2, 3]
>>> next(iter(a[::-1]))
3
>>>
array=[1,2,3,4,5,6,7]
last_element= array[len(array)-1]
last_element
Another simple solution
Couldn't find any answer mentioning this. So adding.
You could try some_list[~0] also.
That's the tilde symbol

Categories