Use split for specific elements of multidimensional list - python

I have the following list (the actual file is much larger and complex)
a = [[['3x5'], ['ff']], [['4x10'], ['gg']]]
I would like to use the split functionality for the first element in the list and get the value in which appears after "x". The final results should be 5 and 10 in this case. I tried to use split in this format
for line in a:
print str(line[0]).split("x")[1]
but the output is
5']
10']
I know I can easily manipulate the output to get 5 and 10 but what is the correct way of using split in this case?
And I am interested in using split for specific element of a list (first elements in this case).

You need to dive one level deeper, and dont use str() on the list.
>>> a = [[['3x5'], ['ff']], [['4x10'], ['gg']]]
>>> for y in a:
... if 'x' in y[0][0]:
... print y[0][0].split('x')[-1]
5
10

You shouldn't the list to a string object, however, you can do it use:
>>> [i[0][0].split('x')[1] for i in a]
['5', '10']
I think you also want to convert the output to int object, then you can simply add an int() like below:
>>> [int(i[0][0].split('x')[1]) for i in a]
[5, 10]
However, if you don't need save the output into a list, but print it out instead, you can just use the same code, but write another version:
a = [[['3x5'], ['ff']], [['4x10'], ['gg']]]
for i in a:
print(i[0][0].split('x')[1])
Output:
5
10
Remember that my code will failed (raise IndexError: list index out of range) when a is... For example [[['3x5'], ['ff']], [['kk'], ['gg']]] (the first element in one of the sublists isn't in format like '3x5').
However, a simple if can fix this:
>>> a = [[['3x5'], ['ff']], [['kk'], ['gg']]]
>>> [int(i[0][0].split('x')[1]) for i in a]
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 1, in <listcomp>
IndexError: list index out of range
>>> [int(i[0][0].split('x')[1]) for i in a if 'x' in i[0][0]]
[5]
Or even better, use RegEx to check, which can avoid something like a = [[['3x5'], ['ff']], [['xxxxxxx'], ['gg']]]:
>>> import re
>>> a = [[['3x5'], ['ff']], [['xxxxxxx'], ['gg']]]
>>> [int(i[0][0].split('x')[1]) for i in a if re.search(r'\d+x\d+', i[0][0])]
[5]
Another way, if you don't want import re:
>>> [int(i[0][0].split('x')[1]) for i in a
... if all(j.isdigit() for j in i[0][0].split('x'))]
[5]

Related

Converting list to string then integer

I have a list with 1550500 numbers, and all of them with quotes.
Example: list('100', '150', '200', '250') etc...
I need to sum all the numbers, but before that I need to convert it to INT.
List Name: trip_list
My code:
mean_tripstr = str(trip_list)
mean_trip = [int(x) for x in mean_tripstr]
print(type(mean_trip))
Error message:
Traceback (most recent call last):
File "projeto1.py", line 235, in <module>
mean_trip = [int(x) for x in mean_tripstr]
File "projeto1.py", line 235, in <listcomp>
mean_trip = [int(x) for x in mean_tripstr]
ValueError: invalid literal for int() with base 10: '['
What am I doing wrong? I am new to coding...
Python has a map function, this takes a function and an iterable. There is also the sum function, which returns the sum of an iterable.
You can use this:
sum(map(int(trip_list))
Note that the map function does not return a list, it returns a generator. To convert it to a list, use
list(sum(map(int, trip_list)))
(this may take a while as it requires iterating over the entire list, and yours is quite long).
The error with your code is converting your list to a string, that is,
>>> my_list = ["5", "6"]
>>> my_list_str = str(my_list)
>>> my_list_str
"['5', '6']"
>>> type(my_list_str)
<class 'str'>
>>> type(my_list)
<class 'list'>
So when you try to iterate over the string, the first x is [ which is not a number (thus the exception).
As a sidenote, using list(map(int, a_list)) is faster than [int(i) for i in a_list]
>>> c1 = "list(map(int, a_list))"
>>> c2 = "[int(i) for i in a_list]"
>>> s = "a_list = [str(i) for i in range(1000)]"
>>> import timeit
>>> timeit.timeit(c1, setup=s, number=10000)
1.9165708439999918
>>> >>> timeit.timeit(c2, setup=s, number=10000)
2.470973639999997
You have to convert each element to int:
mean_tripstr = map(str,trip_list)
mean_trip = list(map(int,mean_tripstr))
The code above uses a generator, what is more efficient in cases when you just have to iterate in a list. The last line convert to a list again properly.
But, as you said, if you already have a list of strings, you can just do:
mean_trip = list(map(int,trip_list))
If you know numpy, you can do too:
import numpy as np
trip_list = np.array(trip_list)
mean_trip = trip_list.astype(np.int)

Behaviour of Python when attempting to iterate over characters in a string

I am attempting to iterate over the following string, using a for loop:
>>> for a,b,c in "cat"
print(a,b,c)
Now what I intended for this to do was print out each character in the string individually on one physical line, instead I receive an error. I am aware that this is very easily resolved by enclosing the string in the list operator []:
>>> for a,b,c in ["cat"]
print(a,b,c)
c a t
But could someone explain why this is the case?
You are telling for to expand each iteration value to assign to three separate variables:
for a,b,c in "cat":
# ^^^^^ the target for the loop variable, 3 different names
However, iteration over a string produces a string with a single character, you can't assign a single character to three variables:
>>> loopiterable = 'cat'
>>> loopiterable[0] # first element
'c'
>>> a, b, c = loopiterable[0]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 1)
The error message tells you why this didn't work; you can't take three values out of a string of length 1.
When you put the string into a list, you changed what you loop over. You now have a list with one element, so the loop iterates just once, and the value for the single iteration is the string 'cat'. That string just happens to have 3 characters, so can be assigned to three variables:
>>> loopiterable = ['cat']
>>> loopiterable[0] # first element
'cat'
>>> a, b, c = loopiterable[0]
>>> a
'c'
>>> b
'a'
>>> c
't'
This still would fail if the contained string has a different number of characters:
>>> for a, b, c in ['cat', 'hamster']:
... print(a, b, c)
...
c a t
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)
'hamster' is 7 characters, not 3; that's 4 too many.
The correct solution is to just use one variable for the loop target, not 3:
for character in 'cat':
print(character)
Now you are printing each character separately:
>>> for character in 'cat':
... print(character)
...
c
a
t
Now, if you wanted to pass all characters of a string to print() as separate arguments, just use * to expand the string to separate arguments to the call:
>>> my_pet = 'cat'
>>> print(*my_pet)
c a t
The for loop goes through each element in the iterable you supply and tries to perform an assignment.
In the first case, since your iterable is 'cat' you're essentially unpacking:
a, b, c = 'c'
during the first iteration and getting the appropriate error message:
ValueError: not enough values to unpack (expected 3, got 1)
because you'll iterate 3 times; once for each character in the string 'cat'.
In the second case, you're unpacking "cat" as expected, because the list has a single element (i.e 'cat') which is retrieved and unpacked into a, b and c.
You are iterating different objects in two blocks of code.
In the former one, you iterate the string, which may be considered a special list.
While in the latter one, you iterate the list which contains only one object 'cat'.
You may change the first one to below:
for ch in 'cat':
print(ch)
Feel free to ask more about this.

Error casting to float, then int in python

Strange error happening.
I know of the issue with trying to cast strings with decimals directly into ints:
int(float('0.0'))
works, while
int('0.0')
does not. However, I'm still getting an error that I can't seem to figure out:
field = line.strip().split()
data[k,:] = [int(float(k)) for k in field[1:]]
ValueError: invalid literal for long() with base 10: '0.0'
Any ideas what could be happening here? The script seems to be thinking it's a cast to long instead of float. Any way to convince it otherwise?
Thanks in advance!
EDIT: the data line is of the form:
'c1c9r2r8\t0.0\t3.4\t2.1\t9.0\n'
It appears that what is happening is that the list comprehension is polluting your namespace.
eg.
k = 0
[k for k in range(10)]
After executing the above code in python 2.x the value of k will be 9 (the last value that was produced by range(10)).
I'll simplify your code to show you what is happening.
>>> l = [None, None, None]
>>> k = 0
>>> l[k] = [k for k in range(3)]
>>> print k, l
2 [None, None, [0, 1, 2]]
You see that l[k] evaluated to l[2] rather than l[0]. To avoid this namespace pollution either do not use the same variable names in a list comprehension as you do in the outer code, or use python 3.x where inner variables of list comprehensions no longer escape to the outer code.
For python 2.x your code should be modified to be something like:
data[k,:] = [int(float(_k)) for _k in field[1:]]
>>> line = 'c1c9r2r8\t0.0\t3.4\t2.1\t9.0\n'
>>> field = line.strip().split()
>>> field
['c1c9r2r8', '0.0', '3.4', '2.1', '9.0']
>>> [int(x) for x in map(float, field[1:])]
[0, 3, 2, 9]
Your error is coming from the left-hand side of the assignment data[k, :] = .... Here you're trying to index a NumPy array (data) with a string (k). NumPy tries to do an implicit conversion of that string to a usable integer index, and fails. For example:
>>> import numpy as np
>>> data = np.arange(12).reshape(3, 4)
>>> data['3.4', :] = 6
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for long() with base 10: '3.4'
Use an integer instead of a string here, and the problem should go away.

Python list append multiple elements

I want to append multiple elements to my list at once. I tried this
>>> l = []
>>> l.append('a')
>>> l
['a']
>>> l.append('b').append('c')
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
l.append('b').append('c')
AttributeError: 'NoneType' object has no attribute 'append'
>>>
how can I append 'b' and 'c' at once?
The method append() works in place. In other words, it modifies the list, and doesn't return a new one.
So, if l.append('b') doesn't return anything (in fact it returns None), you can't do:
l.append('b').append('c')
because it will be equivalent to
None.append('c')
Answering the question: how can I append 'b' and 'c' at once?
You can use extend() in the following way:
l.extend(('b', 'c'))
Use list.extend:
>>> l = []
>>> l.extend(('a', 'b'))
>>> l
['a', 'b']
Note that similar to list.append, list.extend also modifies the list in-place and returns None, so it is not possible to chain these method calls.
But when it comes to string, their methods return a new string. So, we can chain methods call on them:
>>> s = 'foobar'
>>> s.replace('o', '^').replace('a', '*').upper()
'F^^B*R'
l = []
l.extend([1,2,3,4,5])
There is a method for your purpose.

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