Having an issues with list comprehension - python

def divisble_numbers(a_list, terms):
b_list = [x for x in [a_list] if (x % [terms] == 0)]
c_list = [x for x in b_list if all(x % [terms] == 0)]
return c_list
divisble_numbers([2,3,5,1,6,7,8,9,10,11,12], [2,3])
Returns this error: TypeError: unsupported operand type(s) for %: 'int' and 'list'
I am trying to get to get a list of the index that is divisible by both terms. I am confused on the error I am getting, very new to list comprehension would appreciate any help.

You were pretty close. This code should work:
def divisble_numbers(a_list, terms):
return [x for x in a_list if all(x % term == 0 for term in terms)]
print(divisble_numbers([2,3,5,1,6,7,8,9,10,11,12], [2,3]))
# Output:
# [6, 12]
There are two list comprehensions happening here. One is x for x in a_list if .... The other one is inside the all: x % term == 0 for term in terms.

Your list comprehensions are good, but you've accidentally wrapped a few things in square brackets, such as [terms], which don't need to be because they are already lists. [terms] will produce a list containing a list.
Second, the error that you were getting is because you were taking the mod (%) of a list. The mod operator only works between numbers.
def divisble_numbers(a_list, terms):
b_list = [x for x in a_list if (x % terms[0] == 0)]
c_list = [x for x in b_list if (x % terms[1] == 0)]
return c_list

b_list = [x for x in a_list if x%(reduce(lambda x,y : x*y, terms))==0]
Input :
a_list, terms = [2,3,5,1,6,7,8,9,10,11,12], [2,3]
Output :
[6, 12]
Your function will be :
def divisble_numbers(a_list, terms): return [x for x in a_list if x%(reduce(lambda x,y : x*y, terms))==0]

Related

lambda if with list of numbers in python

I try to print from a list, only the organs that match the condition (divided by 2) with the help of a Lambda and something here does not work:
list = list(range(0, 50))
[(lambda x: print(x) if(x % 2 == 0)(x(l)) for l in list]
No need for a lambda for this task, you can just use a list comprehension to generate the sub-list of elements matching the condition:
l = list(range(0, 50))
print([x for x in l if x % 2 == 0])
check it
x = [i for i in range(50) if not i %2]
You don't need to use lambda for this. You can do this way:
list = list(range(50))
[i for i in list if i%2==0]

Avoid computing the same expression twice in list comprehension [duplicate]

This question already has answers here:
Python list comprehension - want to avoid repeated evaluation
(12 answers)
Closed 3 years ago.
I am using a function in a list comprehension and an if function:
new_list = [f(x) for x in old_list if f(x) !=0]
It annoys me that the expression f(x) is computed twice in each loop.
Is there a way to do it in a cleaner way? Something along the lines of storing the value or including the if statement at the beginning of the list comprehension.
Compute the results beforehand and iterate over them
new_list = [x for x in map(f, old_list) if x !=0]
Moreover, since map computes the result per element when the element is accessed this is just one loop.
you could use a generator expression (in order to avoid creating an unnecessary list) inside your list comprehension:
new_list = [fx for fx in (f(x) for x in old_list) if fx != 0]
starting from python 3.8 you will be able to do this:
new_list = [fx for x in old_list if (fx := f(x)) != 0]
in Python 3.8 we'll have the "walrus operator" and be able to do just that!
[y for x in old_list if (y := f(x)) != 0]
You could use a filter to remove results:
def f (x):
return x * 2
old_list = [0, 1, 2, 3]
new_list = filter(lambda x: x != 0, [f(x) for x in old_list])
for x in new_list:
print(x)
See it working here.
Alternatively you could memoize the function so as to prevent ever having to compute the same result twice:
def f (x):
return x * 2
def memoize(f):
memo = {}
def helper(x):
if x not in memo:
print("Computing result for %s" % x)
memo[x] = f(x)
return memo[x]
return helper
memF = memoize(f)
old_list = [0, 1, 2, 3]
new_list = [memF(x) for x in old_list if memF(x) != 0]
for x in new_list:
print(x)
Which is available here.

Selection elements of a list based on another 'True'/'False' list

I have two lists of the same length.
The first one contains strings. The second one - strings that can be either 'True' or 'False'.
If the nth element of the second list is 'True', I want to append the nth element of the first list to another list.
So if I have:
List1:
('sth1','sth2','sth3','sth4')
List2:
('True','False','True','False')
The outcome should be List3:
('sth1','sth3').
How can I intersect two list in that way?
Use zip:
result = [x for x, y in zip(xs, ys) if y == 'True']
Example:
xs = ('sth1','sth2','sth3','sth4')
ys = ('True','False','True','False')
result = [x for x, y in zip(xs, ys) if y == 'True']
result
['sth1', 'sth3']
Or use numpy:
import numpy as np
filtered = np.array(List1)[np.array(List2)]
Btw this only works if the elements inside List2 are True/False, not if they are "True"/"False".
If you didn't know about zip :
l1 = ('sth1','sth2','sth3','sth4')
l2 = ('True','False','True','False')
l = [x for i,x in enumerate(l1) if l2[i]=='True']
print l
#=> ['sth1', 'sth3']
It would be shorter with a tuple of booleans :
l1 = ('sth1','sth2','sth3','sth4')
l2 = (True,False,True,False)
l = [x for i,x in enumerate(l1) if l2[i]]
print l
Simplest way is to use itertools.compress method as follows.
import itertools
list1 = ('sth1','sth2','sth3','sth4')
list2 = ('True','False','True','False')
list2 = map(lambda x: x == 'True', list2)
result = list(itertools.compress(list1, list2))
compress method returns an iterator, so you that is why you need to wrap the iterator object in list
I hope it helps.

Ignoring a value in a list search

I am using lists to store attributes and this problem cropped up when I was searching for equal items:
l = [['a',1,2],['b',1,2],['c',2,3],['d',1,2]]
if [any,1,2] in l:
print ('blue')
elif [any,2,3] in l:
print('red')
desired output
blue
What I want is the first value being ignored/can be any value.
I know the any function doesn't work this way but what is the correct method to doing so?
Perhaps this is more understandable
l = [['a',1,2],['b',1,2],['c',2,3],['d',1,2]]
for a in range(0,4):
if [1,2] == x[1:] for x in l:
print ('blue')
elif [2,3] == x[1:] for x in l:
print('red')
For filtering equal items (according to your definition) you can use list comprehension and slicing:
>>> lst = [['a',1,2],['b',1,2],['c',2,3],['d',1,2]]
>>> [e for e in lst if e[1:] == [1,2]]
[['a', 1, 2], ['b', 1, 2], ['d', 1, 2]]
:D actually managed to do it in one line thanks to pkacprzak.
l = [['a',1,2],['b',1,2],['c',2,3],['d',1,2]]
if any(True for x in l if x[1:] == [1,2]):
print ('blue')
elif any(True for x in l if x[1:] == [2,3]):
print('red')
Code works like this:
True for x in l
iterates over l (<---this is the letter L btw) and returns True if the next bit is True
if x[1:] == [1,2]
this checks all values of x except the first and returns True
any(...)
finds if any of the values returned from the bit inside the any is True
You could also return the value of the first item like so
[x[0] for x in l if x[1:] == [1,2]]
and iterate over that as well
for completely generic case simply introduce some magical symbol to denote 'any' like '*' and write your own simple comparator
def matches(element, mask):
for el, mask_el in zip(element, mask):
if mask_el != '*' and el != mask_el:
return False
return True
and now you can do
for list_el in list:
if matches(list_el, ['*', 1, 2]):
print 'blah'
the nice thing is that it is very generic, and will work with arbitrary number of '*' in your mask.

python - iterating over a subset of a list of tuples

Lets say I have a list of tuples as follows
l = [(4,1), (5,1), (3,2), (7,1), (6,0)]
I would like to iterate over the items where the 2nd element in the tuple is 1?
I can do it using an if condition in the loop, but I was hoping there will a be amore pythonic way of doing it?
Thanks
You can use a list comprehension:
[ x for x in l if x[1] == 1 ]
You can iterate over tuples using generator syntax as well:
for tup in ( x for x in l if x[1] == 1 ):
...
How about
ones = [(x, y) for x, y in l if y == 1]
or
ones = filter(lambda x: x[1] == 1, l)
Just use the if. It's clear and simple.
for x, y in tuples:
if y == 1:
do_whatever_with(x)
Build a generator over it:
has_1 = (tup for tup in l if l[1] == 1)
for item in has_1:
pass
for e in filter(l, lambda x: x[1] == 1):
print e
Try this, using list comprehensions is the pythonic way to solve the problem:
lst = [(4,1), (5,1), (3,2), (7,1), (6,0)]
[(x, y) for x, y in lst if y == 1]
=> [(4, 1), (5, 1), (7, 1)]
Notice how we use tuple unpacking x, y to obtain each of the elements in the pair, and how the condition if y == 1 filters out only those element with value 1 in the second element of the pair. After that, you can do anything you want with the elements found, in particular, I'm reconstructing the original pair in this part at the left: (x, y)
Since you want to iterate, itertools.ifilter is a nice solution:
from itertools import ifilter
iter = ifilter(lambda x: x[1] == 1, l)
for item in iter:
pass

Categories