Can I achieve the same with list comprehension? - list-comprehension

I am a Python beginner.
I spent an hour to do the following task with list comprehensions. Although I could create a list I could use it was not what wanted to get.
Problem:
I have a list of lists consisting of 2 (or possibly more) strings e.g.:
l=[["1","2"], ["3", "4"]]
I wanted to int each element of the nested lists using list comprehensions (if possible).
I could do it using for loops:
list_int=[]
for e in l:
u=[]
for j in e:
u.append(int(j))
if len(u)==len(l[1]):
t.append(u)
Is that also possible using list comprehensions?
Thank you!

l=[["1","2"], ["3", "4"]]
[[int(x) for x in elm] for elm in l]
Output :
[[1, 2], [3, 4]]

In python 2.7
>>> l = [["1","2"],["3","4"]]
>>> l = [[map(int,ls)] for ls in l]
>>> l
[[[1, 2]], [[3, 4]]]
>>>
In python 3.4
>>> l = [["1","2"],["3","4"]]
>>> l = [list(map(int,ls)) for ls in l]
>>> l
[[1, 2], [3, 4]]
>>>

Related

What is the role of [:] in overwriting a list in a for loop?

I came across a weird syntactical approach at work today that I couldn't wrap my head around. Let's say I have the following list:
my_list = [[1, 2, 3], [4, 5, 6]]
My objective is to filter each nested list according to some criteria and overwrite the elements of the list in place. So, let's say I want to remove odd numbers from each nested list such that my_list contains lists of even numbers, where the end result would look like this:
[[2], [4, 6]]
If I try to do this using a simple assignment operator, it doesn't work.
my_list = [[1, 2, 3], [4, 5, 6]]
for l in my_list:
l = [num for num in l if num % 2 == 0]
print(my_list)
Output: [[1, 2, 3], [4, 5, 6]]
However, if I "slice" the list, it provides the expected output.
my_list = [[1, 2, 3], [4, 5, 6]]
for l in my_list:
l[:] = [num for num in l if num % 2 == 0]
print(my_list)
Output: [[2], [4, 6]]
My original hypothesis was that l was a newly created object that didn't actually point to the corresponding object in the list, but comparing the outputs of id(x[i]), id(l), and id(l[:]) (where i is the index of l in x), I realized that l[:] was the one with the differing id. So, if Python is creating a new object when I assign to l[:] then how does Python know to overwrite the existing object of l? Why does this work? And why doesn't the simple assignment operator l = ... work?
It's subtle.
Snippet one:
my_list = [[1, 2, 3], [4, 5, 6]]
for l in my_list:
l = [num for num in l if num % 2 == 0]
Why doesn't this work? Because when you do l = , you're only reassigning the variable l, not making any change to its value.
If we write the loop out "manually", it hopefully will become more clear why this strategy fails:
my_list = [[1, 2, 3], [4, 5, 6]]
# iteration 1
l = my_list[0]
l = [num for num in l if num % 2 == 0]
# iteration 2
l = my_list[1]
l = [num for num in l if num % 2 == 0]
Snippet two:
my_list = [[1, 2, 3], [4, 5, 6]]
for l in my_list:
l[:] = [num for num in l if num % 2 == 0]
Why does this work? Because by using l[:] = , you're actually modifying the value that l references, not just the variable l. Let me elaborate.
Generally speaking, using [:] notation (slice notation) on lists allows one to work with a section of the list.
The simplest use is for getting values out of a list; we can write a[n:k] to get the nth, item n+1st item, etc, up to k-1. For instance:
>>> a = ["a", "very", "fancy", "list"]
>>> print(a[1:3])
['very', 'fancy']
Python also allows use of slice notation on the left-side of a =. In this case, it interprets the notation to mean that we want to update only part of a list. For instance, we can replace "very", "fancy" with "not", "so", "fancy" like so:
>>> print(a)
['a', 'very', 'fancy', 'list']
>>> a[1:3] = ["not", "so", "fancy"]
>>> print(a)
['a', 'not', 'so', 'fancy', 'list']
When using slice syntax, Python also provides some convenient shorthand. Instead of writing [n:k], we can omit n or k or both.
If we omit n, then our slice looks like [:k], and Python understands it to mean "up to k", i.e., the same as [0:k].
If we omit k, then our slice looks like a[n:], and Python understands it to mean "n and after", i.e., the same as a[n:len(a)].
If we omit both, then both rules take place, so a[:] is the same as a[0:len(a)], which is a slice over the entire list.
Examples:
>>> print(a)
['a', 'not', 'so', 'fancy', 'list']
>>> print(a[2:4])
['so', 'fancy']
>>> print(a[:4])
['a', 'not', 'so', 'fancy']
>>> print(a[2:])
['so', 'fancy', 'list']
>>> print(a[:])
['a', 'not', 'so', 'fancy', 'list']
Crucially, this all still applies if we are using our slice on the left-hand side of a =:
>>> print(a)
['a', 'not', 'so', 'fancy', 'list']
>>> a[:4] = ["the", "fanciest"]
>>> print(a)
['the', 'fanciest', 'list']
And using [:] means to replace every item in the list:
>>> print(a)
['the', 'fanciest', 'list']
>>> a[:] = ["something", "completely", "different"]
>>> print(a)
['something', 'completely', 'different']
Okay, so far so good.
They key thing to note is that using slice notation on the left-hand side of a list updates the list in-place. In other words, when I do a[1:3] =, the variable a is never updated; the list that it references is.
We can see this with id(), as you were doing:
>>> print(a)
['something', 'completely', 'different']
>>> print(id(a))
139848671387072
>>> a[1:] = ["truly", "amazing"]
>>> print(a)
['something', 'truly', 'amazing']
>>> print(id(a))
139848671387072
Perhaps more pertinently, this means that if a were a reference to a list within some other object, then using a[:] = will update the list within that object. Like so:
>>> list_of_lists = [ [1, 2], [3, 4], [5, 6] ]
>>> second_list = list_of_lists[1]
>>> print(second_list)
[3, 4]
>>> second_list[1:] = [2, 1, 'boom!']
>>> print(second_list)
[3, 2, 1, 'boom!']
>>> print(list_of_lists)
[[1, 2], [3, 2, 1, 'boom!'], [5, 6]]

How to square each element in 2D list using map function python

I have a 2D list:
list1 = [[2,3,4], [3,2]]
I tried:
print( list(map(lambda x :(x**2), arr1 )))
but it gives error
TypeError: can't multiply sequence by non-int of type 'list'
How can I loop inside a map...?
You can use two maps:
list1 = [[2,3,4], [3,2]]
print(list(map(lambda x :list(map(lambda y: (y**2), x)), list1 )))
It gives the following output
[[4, 9, 16], [9, 4]]
This is cleaner with a list comprehension:
list1 = [[2,3,4], [3,2]]
list1 = [[i ** 2 for i in sublist] for sublist in list1]
print(list1)
# [[4, 9, 16], [9, 4]]
We iterate through the sublists of list1, and for each element in each sublist, we apply the transform -- squaring the number in this case.
I believe a single map and a single list comprehension is the most readable.
list1 = [[2, 3, 4], [3, 2]]
square = lambda x: x**2
squared = [list(map(square, sublist)) for sublist in list1]
you can use this code:
list1 = [[2,3,4], [3,2]]
def power(my_list):
return [ x**2 for x in my_list[i] ]
list=[]
for i in range(len(list1)):
sublist = power(list1)
list.append(sublist)
print(list)
In fact, in this code, you can adjust your power by using the function and changing it.(x ** 3 or x ** 4 and etc).

Python Convert String List to List

So I have a list of python formatted like:
x = ['[1,2,3]', '[4,5,6,]', ...]
Is there a way to convert the "inner lists" to actual lists? So the output would be
x = [[1,2,3], [4,5,6], ....]
Thanks!
Another example with json:
>>> import json
>>> x = ['[1,2,3]', '[4,5,6]']
>>> [json.loads(y) for y in x]
[[1, 2, 3], [4, 5, 6]]
Please limit your strings to dicts and lists only.
You can use ast.literal_eval for this kind of conversion. You can use map to apply the conversion to each element of your list.
from ast import literal_eval
x = ['[1,2,3]', '[4,5,6,]']
x = map(literal_eval, x)
print x
gives
[[1, 2, 3], [4, 5, 6]]
You can use eval to evaluate strings as code.
x = ['[1,2,3]', '[4,5,6,]']
y = [eval(s) for s in x]

Different behavior in list comprehension

In my mind this two pieces of code do the same thing:
l = [[1,2], [3,4],[3,2], [5,4], [4,4],[5,7]]
1)
In [4]: [list(g) for k,g in groupby(sorted(l,key=lambda x:x[1]),
key = lambda x:x[1]) if len(list(g)) == 2]
Out[4]: [[]]
2)
In [5]: groups = [list(g) for k,g in groupby(sorted(l,
key=lambda x:x[1]), key = lambda x:x[1])]
In [6]: [g for g in groups if len(g) == 2]
Out[6]: [[[1, 2], [3, 2]]]
But as you see first one gives an empty list while the second one gives what I need. Where am I mistaken?
The group is an iterator, you cannot consume it (e.g. by calling list on it) twice. For example:
>>> from operator import itemgetter
>>> from itertools import groupby
>>> l = [[1,2], [3,4],[3,2], [5,4], [4,4],[5,7]]
>>> for _, group in groupby(sorted(l, key=itemgetter(1)), key=itemgetter(1)):
... print('first', list(group))
... print('second', list(group))
...
first [[1, 2], [3, 2]]
second []
first [[3, 4], [5, 4], [4, 4]]
second []
first [[5, 7]]
second []
Instead, you need to call list once per group and filter on the results of that, e.g. by using map:
>>> [lst for lst in map(list, (group for _, group in groupby(sorted(l, key=itemgetter(1))), key=itemgetter(1))) if len(lst) == 2]
[[[1, 2], [3, 2]]]

Summing two 2-D lists

so this has kind of stumped me. I feel like it should be an easy problem though.
Lets say I have these two lists
a = [[3, 4], [4, 5]]
b = [[1, 2], [4, 6]]
I am trying so it would return the sum of the two 2-D lists of each corresponding element like so
c = [[4, 6], [8, 11]]
I am pretty sure I am getting lost in loops. I am only trying to use nested loops to produce an answer, any suggestions? I'm trying several different things so my code is not exactly complete or set in stone and will probably change by the time someone reponds so I won't leave a code here. I am trying though!
You could try some variation on nested for-loops using enumerate (which will give you the appropriate indices for comparison to some other 2d array):
a = [[3, 4], [4, 5]]
b = [[1, 2], [4, 6]]
Edit: I didn't see you wanted to populate a new list, so I put that in there:
>>> c = []
>>> for val, item in enumerate(a):
newvals = []
for itemval, insideitem in enumerate(item):
newvals.append(insideitem + b[val][itemval])
c.append(newvals)
newvals = []
Result:
>>> c
[[4, 6], [8, 11]]
Use numpy:
import numpy as np
a = [[3, 4], [4, 5]]
b = [[1, 2], [4, 6]]
c = np.array((a,b))
np.sum(c, axis=0)
I know it is an old question, but following nested loops code works exactly as desired by OP:
sumlist = []
for i, aa in enumerate(a):
for j, bb in enumerate(b):
if i == j:
templist = []
for k in range(2):
templist.append(aa[k]+bb[k])
sumlist.append(templist)
templist = []
print(sumlist)
Output:
[[4, 6], [8, 11]]

Resources