Advanced Nested List Comprehension Syntax
you need to use some parentheses:
((x for x in range(10) if x%2==i) for i in range(2))
This didn't make sense to me, so I
thought it best to try something
simpler first. So I went back to lists
and tried:[>>> [x for x in range(10) if x%2==i for i in range(2)]
[1, 1, 3, 3, 5, 5, 7, 7, 9, 9]
That worked because a previous list comprehension leaks the i variable to the enclosing scope, and become the i for the current one. Try starting a fresh python interpreter, and that would fail due to NameError. The counter's leaking behavior has been removed in Python 3.
EDIT:
The equivalent for loop for:
(x for x in range(10) if x%2==i for i in range(2))
would be:
l = []
for x in range(10):
if x%2 == i:
for i in range(2):
l.append(x)
which also gives a name error.
EDIT2:
the parenthesed version:
((x for x in range(10) if x%2==i) for i in range(2))
is equivalent to:
li = []
for i in range(2):
lx = []
for x in range(10):
if x%2==i:
lx.append(x)
li.append(lx)
Nested if / else clauses in List Comprehension Syntax Error
This will read much more easily as a regular for loop:
new_list = []
for i in old_list:
if not re.findall(r'find_pattern', i, re.M):
new_list.append(re.sub(r'replace_a', 'with_b', i))
elif foo == re.match("pattern", foo):
new_list.append(re.sub(r'replace_c', r'with_d', i))
# else:
# i
Your problem is that a conditional expression must always take an else
clause, because it has to have some value whether or not the condition is true. With an if
statement, however, you can omit the else
. The above, for instance, has the ability to make new_list
shorter than old_list
, as not every i
needs to result in a call to new_list.append
. Uncommenting the else
results in the same result as jpp's answer.
If you insist on using a list comprehension, then you can format it to make it more readable. Consider
new_list = [re.sub(r'replace_pattern_a', 'with_pattern_b', i)
if not re.findall(r'find_pattern', i, re.M) else
re.sub(r'replace_pattern_c', r'with_pattern_d', i)
if foo == re.match("pattern", foo) else
i
for i in old_list]
although the conditional expression really isn't designed for such nesting. This visually separates the expressions that could be added to the new list from the conditions used to make the decision, but I'm not a big fan. There are other ways to format that make different trade-offs, but IMO the regular for
loop is superior.
As jpp mentions, another way to refactor is to define a generator function:
def foo(old_list):
for i in old_list:
if not re.findall(r'find_pattern', i, re.M):
yield re.sub(r'replace_a', 'with_b', i))
elif foo == re.match("pattern", foo):
yield re.sub(r'replace_c', r'with_d', i))
else:
yield i
new_list = list(foo())
which would have its pros and cons as well. (I think enumerating those is probably beyond the scope of this answer, but it does fall somewhere between the two extremes of a single list comprehension and an explicit for
loop. It also comes closest to the construct I miss from my Perl days, the do
statement, which is something like a lambda
that doesn't take any arguments, but can contain arbitrary statements.)
Nested list comprehension to flatten nested list
Your syntax was a little wrong. Try below snippet.
nested_list = [[1,2,3], [4,5,6], [7,8,9]]
odds_evens = ['odd' if n % 2 != 0 else 'even' for l in nested_list for n in l]
print(odds_evens)
Output:
['odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
Nested List Comprehension
Double Iteration in List Comprehension
Gee, I guess I found the anwser: I was not taking care enough about which loop is inner and which is outer. The list comprehension should be like:
[x for b in a for x in b]
to get the desired result, and yes, one current value can be the iterator for the next loop.
Correct syntax for nested list or set comprehension
tags = set(tag for e in my_obj['Episodes'] for tag in e['Tags'])
you need to change the order and get e first... :)
Create a list within a list comprehension
I am guessing you are looking for -
[[char for i,char in enumerate(line) if len(line[i:])>3] for line in grid]
You should move the second for loop and condition inside the list, not the first one. When there were no lists, the order of execution was - first for loop - for line in grid
-> second for loop - for i,char in enumerate(line)
.
The above would preserve that order, and create chars for each line meeting your condition as a separate list.
Python: filtering in nested list comprehension
Other than doing it in one line:
[(i, j) for i, row in enumerate(matrix) for j, el in enumerate(row) if el == 'W']
#[(0, 1), (1, 1), (2, 0)]
You can also use numpy
:
import numpy as np
list(zip(*np.where(np.array(matrix)=='W')))
#[(0, 1), (1, 1), (2, 0)]
Python Nested List Comprehension with If Else
[str.replace(i[0],k,header_replace[k]) if k in i[0] for k in header_replace.keys() for i in cursor.description]
this is a SyntaxError
, because if
expressions must contain the else
part. You probably meant:
[i[0].replace(k, header_replace[k]) for k in header_replace for i in cursor.description if k in i[0]]
With the if
at the end. However I must say that list-comprehension with nested loops aren't usually the way to go.
I would use the expanded for
loop. In fact I'd improve it removing the replaced
flag:
headers = []
for header in cursor.description:
for key, repl in header_replace.items():
if key in header[0]:
headers.append(header[0].replace(key, repl))
break
else:
headers.append(header[0])
The else
of the for
loop is executed when no break
is triggered during the iterations.
I don't understand why in your code you use str.replace(string, substring, replacement)
instead of string.replace(substring, replacement)
. Strings have instance methods, so you them as such and not as if they were static methods of the class.
Nested list comprehension dict and list python
I think you need something like following (if data
is your "list of dicts"):
[d.get('price') for d in data]
What I am doing is, iterating over list of dicts and to each dict use get('price')
(as get()
doesn't throw key exception) to read value of 'price' key.
Note: Avoid to use 'dict' as a variable name as it is in-build type name.
Example:
>>> data = [ {'price': 2, 'b': 20},
{'price': 4, 'a': 20},
{'c': 20}, {'price': 6, 'r': 20} ] # indented by hand
>>> [d.get('price') for d in data]
[2, 4, None, 6]
>>>
You can remove None
in output list, by adding explicit if-check as: [d['price'] for d in data if 'price' in d]
.
Reviews on your code:
[b for a:b in dict.items() if a='price' for dict in data]
You have silly syntax error
a:b
should bea, b
Second, syntax error in if condition —
a='price'
should bea == 'price'
(misspell == operator as =)Order of nested loops are wrong (in list compression we write nested loop later)
This is it not an error, it is but bad practice to use inbuilt type name as variable name. You shouldn't use 'dict', 'list', 'str', etc as variable(or function) name.
Correct form of your code is:
[b for dict in data for a, b in dict.items() if a == 'price' ]
In your list compression expression
for a, b in dict.items() if a == 'price'
loop is unnecessary—simpleget(key)
,setdefualt(key)
or[key]
works faster without loop.
Related Topics
How to Dump a Dict to a JSON File
Process to Convert Simple Python Script into Windows Executable
Programmatically Searching Google in Python Using Custom Search
How to Specify an Authenticated Proxy for a Python Http Connection
Replacing Text in a File with Python
Getting the SQL from a Django Queryset
Heapq with Custom Compare Predicate
Add Sum of Values of Two Lists into New List
Downloading File to Specified Location with Selenium and Python
Rename Specific Column(S) in Pandas
Convert Row to Column Header for Pandas Dataframe,
Python Postgres Psycopg2 Threadedconnectionpool Exhausted
Correct Way to Define Class Variables in Python
Shuffle an Array with Python, Randomize Array Item Order with Python
Random State (Pseudo-Random Number) in Scikit Learn
Global Variable from a Different File Python
It Is More Efficient to Use If-Return-Return or If-Else-Return