Python: What's the "Pythonic" way to process two lists? - python

Say I have this code in Python. I'm a Perl programmer, as you may be able to tell.
# Both list1 and list2 are a list of strings
for x in list1:
for y in list2:
if y in x:
return True
return False
What's a more Pythonic way to handle this? I assume a list comprehension could do it well, but I can't get my head around the "process two separate lists" part of this.

To convert two nested loops into a nested comprehension, you just do this:
[<expression> for x in list1 for y in list2]
If you've never thought through how list comprehensions work, the tutorial explains it:
A list comprehension consists of brackets containing an expression followed by a for clause, then zero or more for or if clauses. The result will be a new list resulting from evaluating the expression in the context of the for and if clauses which follow it.
In other words, the clauses from left to right in a comprehension match up with statements from top/outside to bottom/inside, and that's all there is to it.
This blog post attempts to put the same idea in yet another way, in case you haven't got it yet.
But here, you don't have an expression, you have a statement.
But you have an expression in there, the y in x part of the statement, and what you want to do is return True if it's every true for any value, which is exactly what any does. So:
return any([y in x for x in list1 for y in list2])
And really, you don't want to build the list here, just iterate over the values, so drop the square brackets to make it a generator expression instead:
return any(y in x for x in list1 for y in list2)
For the simple case of just iterating the cartesian products of multiple iterables, you may want to use itertools.product instead. In this case, I don't think it makes things any simpler or more readable, but if you had four lists instead of two—or an unpredictable-in-advance number of them—that might be a different story:
return any(y in x for x, y in product(list1, list2))

No, a list comprehension can't do it well. You want a boolean result, list comprehensions are for creating lists (and they don't really do early exit). You could use a generator comprehension:
return any(y in x for x, y in itertools.product(list1, list2))
or if you really like using standard libraries for everything (or you think like a functional programmer):
from itertools import starmap, product
from operator import contains
return any(starmap(contains, product(list1, list2))

Steve and abamarts answers are explaining what you asked explicitly, i would try to address what you implied regarding list comprehensions.
A "nested" list comprehension is nothing more then your original nested for loop, but with the twist, that the most inner-block moves up to the top!
for x in list1:
for y in list2:
if y in x:
return True
else:
return False
becomes:
[True if y in x else False for x in list1 for y in list2]
So the for-loops remain more or less in order:
[for x in list1 for y in list2]
then prepend the if-clause:
[if y in x else False for x in list1 for y in list2]
and finally prepend the result for the if-statement to be True:
[True if y in x else False for x in list1 for y in list2]
a nested example:
tpl_list = []
for element in vector:
for x, y in element:
if (x**2+y**2) < 1:
tpl_list.append((1/x, 1/y))
else:
tpl_list.append((x,y))
as a list comprehension (building in steps)
[for e in vector for x,y in e]
[if (x**2+y**2) < 1 else for e in vector for x,y in e]
[(1/x, 1/y) if (x**2+y**2) < 1 else (x,y) for e in vector for x,y in e]

Related

get list of elements that don't contain elements in another list

I have the following two lists, one which i want to extract from, and the other is a list that elements from the first list should not contain
as following:
exclude_list = ['not_use', 'dont_use']
feature_list = ['good_use', 'very_good_use', 'hey_not_use', 'hey_dont_use']
desired_list = ['good_use', 'very_good_use']
ret_list = [x for x in feature_list if any(x not in y for y in exclude_list)]
print(ret_list)
assert set(ret_list) == set(desired_list), 'list are not identical'
I tried looking in question such as:
Find elements of a list that contain substrings from another list in Python
But for some kind of reason this one seems to be tricky.
Thanks in advance!
You almost had it:
[x for x in feature_list if not any(y in x for y in exclude_list)]
# ['good_use', 'very_good_use']
Note that the not has to have scope over the any (not the other way round) and that it is y in x, not x in y.

can this be done in one line in python?

I feel this can be done in one line, but I cannot find a way to do.
# final_list is what I want as an output
final_list = []
for x in some_list:
# y is a dictionary
y = x.get_some_dict()
# Want to add a new key/value pair to y, which comes from x
y.update({"new_key": x.property_in_x})
# append y to the output list
final_list.append(y)
return final_list
I wouldn't recommend collapsing this into a one line list comprehension. It can be done, but it's bad style. List comprehensions shouldn't have side effects (i.e. calling update).
You could get replace the explicit list appending with a generator. That wouldn't be a bad idea. And d[k] = v is simpler than d.update({k: v}).
def final_list(some_list):
for x in some_list:
y = x.get_some_dict()
y["new_key"] = x.property_in_x
yield y
I wouldn't recommend damping it into a one liner, which will (probably) be messy and unreadable. Also, the update makes a problem with the one liner solution.
But, In my opinion, this can be simplified, to be clearer:
(Shortened, but not to an unreadable one liner)
for x in some_list:
x.get_some_dict().update({"new_key": x.property_in_x})
final_list = [y.get_some_dict() for y in some_list]
Below is the equivalent list comprehension expression along with for loop as:
final_list = [x.get_some_dict() for x in some_list]
for dict_item, base_item in zip(final_list, some_list):
dict_item["new_key"] = base_item.property_in_x

compactly generate list of list python

I have to create a list of lists (each inner list has n fixed elements). Right now, for n=3 I am doing this:
my_list = []
for x in range(min_inner max_inner + 1):
for y in range(min_outer, max_outer + 1):
for z in range(fixed_param):
my_list.append([x, y, z])
When I tried list comprehension, something like:
[[x,y,z] for x in range(1,4), y in range(1,4), z in range (4)]
I get a name error
NameError: name 'z' is not defined
Is there a list comprehension way of doing that? Considering that n can be any number (though not necessarily arbitrarily large)
You need to loop over your range objects inside the list comprehension too.
[[x,y,z] for x in range(1,4) for y in range(1,4) for z in range (4)]
Also as a more concise way you could use itertools.product() to achieve the same result:
from itertools import product
list(product(range(1,4),range(1,4),range(4)))
Note that itertools.product() returns an iterator object which is pretty more optimized (in terms of memory usage) than list comprehension which returns a list. And if you just want to iterate over the result you don't need to convert the result to list. Otherwise the list comprehension will performs faster.

Reference value of expression inside list comprehension in Python?

If I have a list comprehension like
[mymap.get(x, None) for x in oldlist if mymap.get(x,None)]
Is there a way to do mymap.get(x,None) only once here?
I imagine something like
[y for x in oldlist if mymap.get(x,None) as y]
but currently this is a SyntaxError in py 2.x. I would like to be able to reference the resulting values of either the "expression" of list comprehension or from the "list_if" part of it.
I've also tried
[_ for x in oldlist if mymap.get(x,None)]
but that's a NameError, I guess _ being only some interpreter feature on lines.
edit
Is there a way to reference this temporary/anonymous/unnamed variable somehow, without re-iterating the list?
[y for y in (mymap.get(x, None) for x in oldlist) if y]
filter(None, (mymap.get(x, None) for x in oldlist))
or if it suits your fancy the equivalent code using bool instead
filter(bool, (mymap.get(x, None) for x in oldlist))
And to answer your question, there's no way to reference the output function from the predicate.

Comprehension list on nested list (list of lists)

It is allowed the use of a comprehension list on a "list of lists"?
I would like to extract a list from a nested list.
I did try this:
def main():
a = ['1','2','3']
b = ['4','5','6']
c = ['7','8','9']
board = [a,b,c]
y = [x for x in board[1][i] if i in range(0,3)]
print y
but I get "NameError: name 'i' is not defined".
I'm using the wrong syntax or nested list cannot be used like this?
Thanks a lot!
Nesting loops in list comprehensions work the same way as nesting regular for loops, one inside the other:
y = [x for i in range(3) for x in board[1][i]]
but in this case, just selecting board[1][:] would be easier and give you the same result; a copy of the middle row.
If you need to apply an expression to each column in that row, then just loop over board[1] directly:
y = [foobar(c) for c in board[1]]

Categories

Resources