Skipping an element in a one line for-loop statement - python

Is there a way to skip an iteration of the for-loop while using
[x if cond else pass for x in seq]
I get a syntax error while trying it.
Output >>> File "<ipython-input-122-a943adcf1b68>", line 1
test = [pass if isinstance(x, float) else x for x in test_list]
^
SyntaxError: invalid syntax

You are confusing a conditional expression with a loop filter. To filter elements in a list comprehension, put the if after the for loop it filters:
[x for x in seq if cond]
A conditional expression (expr1 if cond else expr2) must always produce a value, because it is an expression. pass is not an expression, it is a statement, and can only ever used by itself.
For your concrete example, where you want to select elements where the values are not floats, you want to use not in the filter test:
[x for x in test_list if not isinstance(x, float)]

Related

List comprehension with If vs If else [duplicate]

I have a list xs containing a mixture of strings and None values. How can I use a list comprehension to call a function on each string, but convert the None values to '' (rather than passing them to the function)?
I tried:
[f(x) for x in xs if x is not None else '']
but it gives a SyntaxError. What is the correct syntax?
See List comprehension with condition if you are trying to make a list comprehension that omits values based on a condition.
If you need to consider more than two conditional outcomes, beware that Python's conditional expressions do not support elif. Instead, it is necessary to nest if/else conditionals. See `elif` in list comprehension conditionals for details.
You can totally do that. It's just an ordering issue:
[f(x) if x is not None else '' for x in xs]
In general,
[f(x) if condition else g(x) for x in sequence]
And, for list comprehensions with if conditions only,
[f(x) for x in sequence if condition]
Note that this actually uses a different language construct, a conditional expression, which itself is not part of the comprehension syntax, while the if after the for…in is part of list comprehensions and used to filter elements from the source iterable.
Conditional expressions can be used in all kinds of situations where you want to choose between two expression values based on some condition. This does the same as the ternary operator ?: that exists in other languages. For example:
value = 123
print(value, 'is', 'even' if value % 2 == 0 else 'odd')
Let's use this question to review some concepts. I think it's good to first see the fundamentals so you can extrapolate to different cases.
Other answers provide the specific answer to your question. I'll first give some general context and then I'll answer the question.
Fundamentals
if/else statements in list comprehensions involve two things:
List comprehensions
Conditional expressions (Ternary operators)
1. List comprehensions
They provide a concise way to create lists.
Its structure consists of: "brackets containing an expression followed by a for clause, then zero or more for or if clauses".
Case 1
Here we have no condition. Each item from the iterable is added to new_list.
new_list = [expression for item in iterable]
new_list = [x for x in range(1, 10)]
> [1, 2, 3, 4, 5, 6, 7, 8, 9]
Case 2
Here we have one condition.
Example 1
Condition: only even numbers will be added to new_list.
new_list = [expression for item in iterable if condition == True]
new_list = [x for x in range(1, 10) if x % 2 == 0]
> [2, 4, 6, 8]
Example 2
Condition: only even numbers that are multiple of 3 will be added to new_list.
new_list = [expression for item in iterable if condition == True]
new_list = [x for x in range(1, 10) if x % 2 == 0 if x % 3 == 0]
> [6]
But howcome we have one condition if we use two if in new_list?
The prior expression could be written as:
new_list = [x for x in range(1, 10) if x % 2 and x % 3 == 0]
> [6]
We only use one if statement.
This is like doing:
new_list = []
for x in range(1, 10):
if x % 2 == 0 and x % 3 == 0:
new_list.append(x)
> [6]
Example 3
Just for the sake of argument, you can also use or.
Condition: even numbers or numbers multiple of 3 will be added to new_list.
new_list = [x for x in range(1, 10) if x % 2 == 0 or x % 3 == 0]
> [2, 3, 4, 6, 8, 9]
Case 3
More than one condition:
Here we need the help of conditional expressions (Ternary operators).
2.Conditional Expressions
What are conditional expressions? What the name says: a Python expression that has some condition.
<Exp1> if condition else <Exp2>
First the condition is evaluated. If condition is True, then <Exp1> is evaluated and returned. If condition is False, then <Exp2> is evaluated and returned.
A conditional expression with more than one condition:
<Exp1> if condition else <Exp2> if condition else <Exp3>...
An example from Real Python:
age = 12
s = 'minor' if age < 21 else 'adult'
> minor
The value of s is conditioned to age value.
3.List Comprehensions with Conditionals
We put list comprehensions and conditionals together like this.
new_list = [<Conditional Expression> for <item> in <iterable>]
new_list = [<Exp1> if condition else <Exp2> if condition else <Exp3> for <item> in <iterable>]
Condition: even numbers will be added as 'even', the number three will be added as 'number three' and the rest will be added as 'odd'.
new_list = ['even' if x % 2 == 0 else 'number three' if x == 3 else 'odd'
for x in range(1, 10)]
> ['odd', 'even', 'number three', 'even', 'odd', 'even', 'odd', 'even', 'odd']
The answer to the question
[f(x) for x in xs if x is not None else '']
Here we have a problem with the structure of the list: for x in xs should be at the end of the expression.
Correct way:
[f(x) if x is not None else '' for x in xs]
Further reading:
Does Python have a ternary conditional operator?
The specific problem has already been solved in previous answers, so I will address the general idea of using conditionals inside list comprehensions.
Here is an example that shows how conditionals can be written inside a list comprehension:
X = [1.5, 2.3, 4.4, 5.4, 'n', 1.5, 5.1, 'a'] # Original list
# Extract non-strings from X to new list
X_non_str = [el for el in X if not isinstance(el, str)] # When using only 'if', put 'for' in the beginning
# Change all strings in X to 'b', preserve everything else as is
X_str_changed = ['b' if isinstance(el, str) else el for el in X] # When using 'if' and 'else', put 'for' in the end
Note that in the first list comprehension for X_non_str, the order is:
expression for item in iterable if condition
and in the last list comprehension for X_str_changed, the order is:
expression1 if condition else expression2 for item in iterable
I always find it hard to remember that expression1 has to be before if and expression2 has to be after else. My head wants both to be either before or after.
I guess it is designed like that because it resembles normal language, e.g. "I want to stay inside if it rains, else I want to go outside"
In plain English the two types of list comprehensions mentioned above could be stated as:
With only if:
extract_apple for apple in apple_box if apple_is_ripe
and with if/else
mark_apple if apple_is_ripe else leave_it_unmarked for apple in apple_box
One way:
def change(x):
if x is None:
return f(x)
else:
return ''
result = [change(x) for x in xs]
Although then you have:
result = map(change, xs)
Or you can use a lambda inline.
Here is another illustrative example:
>>> print(", ".join(["ha" if i else "Ha" for i in range(3)]) + "!")
Ha, ha, ha!
It exploits the fact that if i evaluates to False for 0 and to True for all other values generated by the function range(). Therefore the list comprehension evaluates as follows:
>>> ["ha" if i else "Ha" for i in range(3)]
['Ha', 'ha', 'ha']
[f(x) if x != None else '' for x in xs]
Syntax for list comprehension:
[item if condition else item for item in items]
[f(item) if condition else value for item in items]
[item if condition for item in items]
[value if condition else value1 if condition1 else value2]
The other solutions are great for a single if / else construct. However, ternary statements within list comprehensions are arguably difficult to read.
Using a function aids readability, but such a solution is difficult to extend or adapt in a workflow where the mapping is an input. A dictionary can alleviate these concerns:
xs = [None, 'This', 'is', 'a', 'filler', 'test', 'string', None]
d = {None: '', 'filler': 'manipulated'}
res = [d.get(x, x) for x in xs]
print(res)
['', 'This', 'is', 'a', 'manipulated', 'test', 'string', '']
It has to do with how the list comprehension is performed.
Keep in mind the following:
[ expression for item in list if conditional ]
Is equivalent to:
for item in list:
if conditional:
expression
Where the expression is in a slightly different format (think switching the subject and verb order in a sentence).
Therefore, your code [x+1 for x in l if x >= 45] does this:
for x in l:
if x >= 45:
x+1
However, this code [x+1 if x >= 45 else x+5 for x in l] does this (after rearranging the expression):
for x in l:
if x>=45: x+1
else: x+5
Make a list from items in an iterable
It seems best to first generalize all the possible forms rather than giving specific answers to questions. Otherwise, the reader won't know how the answer was determined. Here are a few generalized forms I thought up before I got a headache trying to decide if a final else' clause could be used in the last form.
[expression1(item) for item in iterable]
[expression1(item) if conditional1 for item in iterable]
[expression1(item) if conditional1 else expression2(item) for item in iterable]
[expression1(item) if conditional1 else expression2(item) for item in iterable if conditional2]
The value of item doesn't need to be used in any of the conditional clauses. A conditional3 can be used as a switch to either add or not add a value to the output list.
For example, to create a new list that eliminates empty strings or whitespace strings from the original list of strings:
newlist = [s for s in firstlist if s.strip()]
There isn't any need for ternary if/then/else. In my opinion your question calls for this answer:
row = [unicode((x or '').strip()) for x in row]
You can combine conditional logic in a comprehension:
ps = PorterStemmer()
stop_words_english = stopwords.words('english')
best = sorted(word_scores.items(), key=lambda x: x[1], reverse=True)[:10000]
bestwords = set([w for w, s in best])
def best_word_feats(words):
return dict([(word, True) for word in words if word in bestwords])
# with stemmer
def best_word_feats_stem(words):
return dict([(ps.stem(word), True) for word in words if word in bestwords])
# with stemmer and not stopwords
def best_word_feats_stem_stop(words):
return dict([(ps.stem(word), True) for word in words if word in bestwords and word not in stop_words_english])
# coding=utf-8
def my_function_get_list():
my_list = [0, 1, 2, 3, 4, 5]
# You may use map() to convert each item in the list to a string,
# and then join them to print my_list
print("Affichage de my_list [{0}]".format(', '.join(map(str, my_list))))
return my_list
my_result_list = [
(
number_in_my_list + 4, # Condition is False : append number_in_my_list + 4 in my_result_list
number_in_my_list * 2 # Condition is True : append number_in_my_list * 2 in my_result_list
)
[number_in_my_list % 2 == 0] # [Condition] If the number in my list is even
for number_in_my_list in my_function_get_list() # For each number in my list
]
print("Affichage de my_result_list [{0}]".format(', '.join(map(str, my_result_list))))
(venv) $ python list_comp.py
Affichage de my_list [0, 1, 2, 3, 4, 5]
Affichage de my_result_list [0, 5, 4, 7, 8, 9]
So, for you:
row = [('', unicode(x.strip()))[x is not None] for x in row]

How do I use an if... else conditional in the inner loop of a nested list comprehension in Python? [duplicate]

I have a list xs containing a mixture of strings and None values. How can I use a list comprehension to call a function on each string, but convert the None values to '' (rather than passing them to the function)?
I tried:
[f(x) for x in xs if x is not None else '']
but it gives a SyntaxError. What is the correct syntax?
See List comprehension with condition if you are trying to make a list comprehension that omits values based on a condition.
If you need to consider more than two conditional outcomes, beware that Python's conditional expressions do not support elif. Instead, it is necessary to nest if/else conditionals. See `elif` in list comprehension conditionals for details.
You can totally do that. It's just an ordering issue:
[f(x) if x is not None else '' for x in xs]
In general,
[f(x) if condition else g(x) for x in sequence]
And, for list comprehensions with if conditions only,
[f(x) for x in sequence if condition]
Note that this actually uses a different language construct, a conditional expression, which itself is not part of the comprehension syntax, while the if after the for…in is part of list comprehensions and used to filter elements from the source iterable.
Conditional expressions can be used in all kinds of situations where you want to choose between two expression values based on some condition. This does the same as the ternary operator ?: that exists in other languages. For example:
value = 123
print(value, 'is', 'even' if value % 2 == 0 else 'odd')
Let's use this question to review some concepts. I think it's good to first see the fundamentals so you can extrapolate to different cases.
Other answers provide the specific answer to your question. I'll first give some general context and then I'll answer the question.
Fundamentals
if/else statements in list comprehensions involve two things:
List comprehensions
Conditional expressions (Ternary operators)
1. List comprehensions
They provide a concise way to create lists.
Its structure consists of: "brackets containing an expression followed by a for clause, then zero or more for or if clauses".
Case 1
Here we have no condition. Each item from the iterable is added to new_list.
new_list = [expression for item in iterable]
new_list = [x for x in range(1, 10)]
> [1, 2, 3, 4, 5, 6, 7, 8, 9]
Case 2
Here we have one condition.
Example 1
Condition: only even numbers will be added to new_list.
new_list = [expression for item in iterable if condition == True]
new_list = [x for x in range(1, 10) if x % 2 == 0]
> [2, 4, 6, 8]
Example 2
Condition: only even numbers that are multiple of 3 will be added to new_list.
new_list = [expression for item in iterable if condition == True]
new_list = [x for x in range(1, 10) if x % 2 == 0 if x % 3 == 0]
> [6]
But howcome we have one condition if we use two if in new_list?
The prior expression could be written as:
new_list = [x for x in range(1, 10) if x % 2 and x % 3 == 0]
> [6]
We only use one if statement.
This is like doing:
new_list = []
for x in range(1, 10):
if x % 2 == 0 and x % 3 == 0:
new_list.append(x)
> [6]
Example 3
Just for the sake of argument, you can also use or.
Condition: even numbers or numbers multiple of 3 will be added to new_list.
new_list = [x for x in range(1, 10) if x % 2 == 0 or x % 3 == 0]
> [2, 3, 4, 6, 8, 9]
Case 3
More than one condition:
Here we need the help of conditional expressions (Ternary operators).
2.Conditional Expressions
What are conditional expressions? What the name says: a Python expression that has some condition.
<Exp1> if condition else <Exp2>
First the condition is evaluated. If condition is True, then <Exp1> is evaluated and returned. If condition is False, then <Exp2> is evaluated and returned.
A conditional expression with more than one condition:
<Exp1> if condition else <Exp2> if condition else <Exp3>...
An example from Real Python:
age = 12
s = 'minor' if age < 21 else 'adult'
> minor
The value of s is conditioned to age value.
3.List Comprehensions with Conditionals
We put list comprehensions and conditionals together like this.
new_list = [<Conditional Expression> for <item> in <iterable>]
new_list = [<Exp1> if condition else <Exp2> if condition else <Exp3> for <item> in <iterable>]
Condition: even numbers will be added as 'even', the number three will be added as 'number three' and the rest will be added as 'odd'.
new_list = ['even' if x % 2 == 0 else 'number three' if x == 3 else 'odd'
for x in range(1, 10)]
> ['odd', 'even', 'number three', 'even', 'odd', 'even', 'odd', 'even', 'odd']
The answer to the question
[f(x) for x in xs if x is not None else '']
Here we have a problem with the structure of the list: for x in xs should be at the end of the expression.
Correct way:
[f(x) if x is not None else '' for x in xs]
Further reading:
Does Python have a ternary conditional operator?
The specific problem has already been solved in previous answers, so I will address the general idea of using conditionals inside list comprehensions.
Here is an example that shows how conditionals can be written inside a list comprehension:
X = [1.5, 2.3, 4.4, 5.4, 'n', 1.5, 5.1, 'a'] # Original list
# Extract non-strings from X to new list
X_non_str = [el for el in X if not isinstance(el, str)] # When using only 'if', put 'for' in the beginning
# Change all strings in X to 'b', preserve everything else as is
X_str_changed = ['b' if isinstance(el, str) else el for el in X] # When using 'if' and 'else', put 'for' in the end
Note that in the first list comprehension for X_non_str, the order is:
expression for item in iterable if condition
and in the last list comprehension for X_str_changed, the order is:
expression1 if condition else expression2 for item in iterable
I always find it hard to remember that expression1 has to be before if and expression2 has to be after else. My head wants both to be either before or after.
I guess it is designed like that because it resembles normal language, e.g. "I want to stay inside if it rains, else I want to go outside"
In plain English the two types of list comprehensions mentioned above could be stated as:
With only if:
extract_apple for apple in apple_box if apple_is_ripe
and with if/else
mark_apple if apple_is_ripe else leave_it_unmarked for apple in apple_box
One way:
def change(x):
if x is None:
return f(x)
else:
return ''
result = [change(x) for x in xs]
Although then you have:
result = map(change, xs)
Or you can use a lambda inline.
Here is another illustrative example:
>>> print(", ".join(["ha" if i else "Ha" for i in range(3)]) + "!")
Ha, ha, ha!
It exploits the fact that if i evaluates to False for 0 and to True for all other values generated by the function range(). Therefore the list comprehension evaluates as follows:
>>> ["ha" if i else "Ha" for i in range(3)]
['Ha', 'ha', 'ha']
[f(x) if x != None else '' for x in xs]
Syntax for list comprehension:
[item if condition else item for item in items]
[f(item) if condition else value for item in items]
[item if condition for item in items]
[value if condition else value1 if condition1 else value2]
The other solutions are great for a single if / else construct. However, ternary statements within list comprehensions are arguably difficult to read.
Using a function aids readability, but such a solution is difficult to extend or adapt in a workflow where the mapping is an input. A dictionary can alleviate these concerns:
xs = [None, 'This', 'is', 'a', 'filler', 'test', 'string', None]
d = {None: '', 'filler': 'manipulated'}
res = [d.get(x, x) for x in xs]
print(res)
['', 'This', 'is', 'a', 'manipulated', 'test', 'string', '']
It has to do with how the list comprehension is performed.
Keep in mind the following:
[ expression for item in list if conditional ]
Is equivalent to:
for item in list:
if conditional:
expression
Where the expression is in a slightly different format (think switching the subject and verb order in a sentence).
Therefore, your code [x+1 for x in l if x >= 45] does this:
for x in l:
if x >= 45:
x+1
However, this code [x+1 if x >= 45 else x+5 for x in l] does this (after rearranging the expression):
for x in l:
if x>=45: x+1
else: x+5
Make a list from items in an iterable
It seems best to first generalize all the possible forms rather than giving specific answers to questions. Otherwise, the reader won't know how the answer was determined. Here are a few generalized forms I thought up before I got a headache trying to decide if a final else' clause could be used in the last form.
[expression1(item) for item in iterable]
[expression1(item) if conditional1 for item in iterable]
[expression1(item) if conditional1 else expression2(item) for item in iterable]
[expression1(item) if conditional1 else expression2(item) for item in iterable if conditional2]
The value of item doesn't need to be used in any of the conditional clauses. A conditional3 can be used as a switch to either add or not add a value to the output list.
For example, to create a new list that eliminates empty strings or whitespace strings from the original list of strings:
newlist = [s for s in firstlist if s.strip()]
There isn't any need for ternary if/then/else. In my opinion your question calls for this answer:
row = [unicode((x or '').strip()) for x in row]
You can combine conditional logic in a comprehension:
ps = PorterStemmer()
stop_words_english = stopwords.words('english')
best = sorted(word_scores.items(), key=lambda x: x[1], reverse=True)[:10000]
bestwords = set([w for w, s in best])
def best_word_feats(words):
return dict([(word, True) for word in words if word in bestwords])
# with stemmer
def best_word_feats_stem(words):
return dict([(ps.stem(word), True) for word in words if word in bestwords])
# with stemmer and not stopwords
def best_word_feats_stem_stop(words):
return dict([(ps.stem(word), True) for word in words if word in bestwords and word not in stop_words_english])
# coding=utf-8
def my_function_get_list():
my_list = [0, 1, 2, 3, 4, 5]
# You may use map() to convert each item in the list to a string,
# and then join them to print my_list
print("Affichage de my_list [{0}]".format(', '.join(map(str, my_list))))
return my_list
my_result_list = [
(
number_in_my_list + 4, # Condition is False : append number_in_my_list + 4 in my_result_list
number_in_my_list * 2 # Condition is True : append number_in_my_list * 2 in my_result_list
)
[number_in_my_list % 2 == 0] # [Condition] If the number in my list is even
for number_in_my_list in my_function_get_list() # For each number in my list
]
print("Affichage de my_result_list [{0}]".format(', '.join(map(str, my_result_list))))
(venv) $ python list_comp.py
Affichage de my_list [0, 1, 2, 3, 4, 5]
Affichage de my_result_list [0, 5, 4, 7, 8, 9]
So, for you:
row = [('', unicode(x.strip()))[x is not None] for x in row]

Python if else within list comprehension [duplicate]

I have a list xs containing a mixture of strings and None values. How can I use a list comprehension to call a function on each string, but convert the None values to '' (rather than passing them to the function)?
I tried:
[f(x) for x in xs if x is not None else '']
but it gives a SyntaxError. What is the correct syntax?
See List comprehension with condition if you are trying to make a list comprehension that omits values based on a condition.
If you need to consider more than two conditional outcomes, beware that Python's conditional expressions do not support elif. Instead, it is necessary to nest if/else conditionals. See `elif` in list comprehension conditionals for details.
You can totally do that. It's just an ordering issue:
[f(x) if x is not None else '' for x in xs]
In general,
[f(x) if condition else g(x) for x in sequence]
And, for list comprehensions with if conditions only,
[f(x) for x in sequence if condition]
Note that this actually uses a different language construct, a conditional expression, which itself is not part of the comprehension syntax, while the if after the for…in is part of list comprehensions and used to filter elements from the source iterable.
Conditional expressions can be used in all kinds of situations where you want to choose between two expression values based on some condition. This does the same as the ternary operator ?: that exists in other languages. For example:
value = 123
print(value, 'is', 'even' if value % 2 == 0 else 'odd')
Let's use this question to review some concepts. I think it's good to first see the fundamentals so you can extrapolate to different cases.
Other answers provide the specific answer to your question. I'll first give some general context and then I'll answer the question.
Fundamentals
if/else statements in list comprehensions involve two things:
List comprehensions
Conditional expressions (Ternary operators)
1. List comprehensions
They provide a concise way to create lists.
Its structure consists of: "brackets containing an expression followed by a for clause, then zero or more for or if clauses".
Case 1
Here we have no condition. Each item from the iterable is added to new_list.
new_list = [expression for item in iterable]
new_list = [x for x in range(1, 10)]
> [1, 2, 3, 4, 5, 6, 7, 8, 9]
Case 2
Here we have one condition.
Example 1
Condition: only even numbers will be added to new_list.
new_list = [expression for item in iterable if condition == True]
new_list = [x for x in range(1, 10) if x % 2 == 0]
> [2, 4, 6, 8]
Example 2
Condition: only even numbers that are multiple of 3 will be added to new_list.
new_list = [expression for item in iterable if condition == True]
new_list = [x for x in range(1, 10) if x % 2 == 0 if x % 3 == 0]
> [6]
But howcome we have one condition if we use two if in new_list?
The prior expression could be written as:
new_list = [x for x in range(1, 10) if x % 2 and x % 3 == 0]
> [6]
We only use one if statement.
This is like doing:
new_list = []
for x in range(1, 10):
if x % 2 == 0 and x % 3 == 0:
new_list.append(x)
> [6]
Example 3
Just for the sake of argument, you can also use or.
Condition: even numbers or numbers multiple of 3 will be added to new_list.
new_list = [x for x in range(1, 10) if x % 2 == 0 or x % 3 == 0]
> [2, 3, 4, 6, 8, 9]
Case 3
More than one condition:
Here we need the help of conditional expressions (Ternary operators).
2.Conditional Expressions
What are conditional expressions? What the name says: a Python expression that has some condition.
<Exp1> if condition else <Exp2>
First the condition is evaluated. If condition is True, then <Exp1> is evaluated and returned. If condition is False, then <Exp2> is evaluated and returned.
A conditional expression with more than one condition:
<Exp1> if condition else <Exp2> if condition else <Exp3>...
An example from Real Python:
age = 12
s = 'minor' if age < 21 else 'adult'
> minor
The value of s is conditioned to age value.
3.List Comprehensions with Conditionals
We put list comprehensions and conditionals together like this.
new_list = [<Conditional Expression> for <item> in <iterable>]
new_list = [<Exp1> if condition else <Exp2> if condition else <Exp3> for <item> in <iterable>]
Condition: even numbers will be added as 'even', the number three will be added as 'number three' and the rest will be added as 'odd'.
new_list = ['even' if x % 2 == 0 else 'number three' if x == 3 else 'odd'
for x in range(1, 10)]
> ['odd', 'even', 'number three', 'even', 'odd', 'even', 'odd', 'even', 'odd']
The answer to the question
[f(x) for x in xs if x is not None else '']
Here we have a problem with the structure of the list: for x in xs should be at the end of the expression.
Correct way:
[f(x) if x is not None else '' for x in xs]
Further reading:
Does Python have a ternary conditional operator?
The specific problem has already been solved in previous answers, so I will address the general idea of using conditionals inside list comprehensions.
Here is an example that shows how conditionals can be written inside a list comprehension:
X = [1.5, 2.3, 4.4, 5.4, 'n', 1.5, 5.1, 'a'] # Original list
# Extract non-strings from X to new list
X_non_str = [el for el in X if not isinstance(el, str)] # When using only 'if', put 'for' in the beginning
# Change all strings in X to 'b', preserve everything else as is
X_str_changed = ['b' if isinstance(el, str) else el for el in X] # When using 'if' and 'else', put 'for' in the end
Note that in the first list comprehension for X_non_str, the order is:
expression for item in iterable if condition
and in the last list comprehension for X_str_changed, the order is:
expression1 if condition else expression2 for item in iterable
I always find it hard to remember that expression1 has to be before if and expression2 has to be after else. My head wants both to be either before or after.
I guess it is designed like that because it resembles normal language, e.g. "I want to stay inside if it rains, else I want to go outside"
In plain English the two types of list comprehensions mentioned above could be stated as:
With only if:
extract_apple for apple in apple_box if apple_is_ripe
and with if/else
mark_apple if apple_is_ripe else leave_it_unmarked for apple in apple_box
One way:
def change(x):
if x is None:
return f(x)
else:
return ''
result = [change(x) for x in xs]
Although then you have:
result = map(change, xs)
Or you can use a lambda inline.
Here is another illustrative example:
>>> print(", ".join(["ha" if i else "Ha" for i in range(3)]) + "!")
Ha, ha, ha!
It exploits the fact that if i evaluates to False for 0 and to True for all other values generated by the function range(). Therefore the list comprehension evaluates as follows:
>>> ["ha" if i else "Ha" for i in range(3)]
['Ha', 'ha', 'ha']
[f(x) if x != None else '' for x in xs]
Syntax for list comprehension:
[item if condition else item for item in items]
[f(item) if condition else value for item in items]
[item if condition for item in items]
[value if condition else value1 if condition1 else value2]
The other solutions are great for a single if / else construct. However, ternary statements within list comprehensions are arguably difficult to read.
Using a function aids readability, but such a solution is difficult to extend or adapt in a workflow where the mapping is an input. A dictionary can alleviate these concerns:
xs = [None, 'This', 'is', 'a', 'filler', 'test', 'string', None]
d = {None: '', 'filler': 'manipulated'}
res = [d.get(x, x) for x in xs]
print(res)
['', 'This', 'is', 'a', 'manipulated', 'test', 'string', '']
It has to do with how the list comprehension is performed.
Keep in mind the following:
[ expression for item in list if conditional ]
Is equivalent to:
for item in list:
if conditional:
expression
Where the expression is in a slightly different format (think switching the subject and verb order in a sentence).
Therefore, your code [x+1 for x in l if x >= 45] does this:
for x in l:
if x >= 45:
x+1
However, this code [x+1 if x >= 45 else x+5 for x in l] does this (after rearranging the expression):
for x in l:
if x>=45: x+1
else: x+5
Make a list from items in an iterable
It seems best to first generalize all the possible forms rather than giving specific answers to questions. Otherwise, the reader won't know how the answer was determined. Here are a few generalized forms I thought up before I got a headache trying to decide if a final else' clause could be used in the last form.
[expression1(item) for item in iterable]
[expression1(item) if conditional1 for item in iterable]
[expression1(item) if conditional1 else expression2(item) for item in iterable]
[expression1(item) if conditional1 else expression2(item) for item in iterable if conditional2]
The value of item doesn't need to be used in any of the conditional clauses. A conditional3 can be used as a switch to either add or not add a value to the output list.
For example, to create a new list that eliminates empty strings or whitespace strings from the original list of strings:
newlist = [s for s in firstlist if s.strip()]
There isn't any need for ternary if/then/else. In my opinion your question calls for this answer:
row = [unicode((x or '').strip()) for x in row]
You can combine conditional logic in a comprehension:
ps = PorterStemmer()
stop_words_english = stopwords.words('english')
best = sorted(word_scores.items(), key=lambda x: x[1], reverse=True)[:10000]
bestwords = set([w for w, s in best])
def best_word_feats(words):
return dict([(word, True) for word in words if word in bestwords])
# with stemmer
def best_word_feats_stem(words):
return dict([(ps.stem(word), True) for word in words if word in bestwords])
# with stemmer and not stopwords
def best_word_feats_stem_stop(words):
return dict([(ps.stem(word), True) for word in words if word in bestwords and word not in stop_words_english])
# coding=utf-8
def my_function_get_list():
my_list = [0, 1, 2, 3, 4, 5]
# You may use map() to convert each item in the list to a string,
# and then join them to print my_list
print("Affichage de my_list [{0}]".format(', '.join(map(str, my_list))))
return my_list
my_result_list = [
(
number_in_my_list + 4, # Condition is False : append number_in_my_list + 4 in my_result_list
number_in_my_list * 2 # Condition is True : append number_in_my_list * 2 in my_result_list
)
[number_in_my_list % 2 == 0] # [Condition] If the number in my list is even
for number_in_my_list in my_function_get_list() # For each number in my list
]
print("Affichage de my_result_list [{0}]".format(', '.join(map(str, my_result_list))))
(venv) $ python list_comp.py
Affichage de my_list [0, 1, 2, 3, 4, 5]
Affichage de my_result_list [0, 5, 4, 7, 8, 9]
So, for you:
row = [('', unicode(x.strip()))[x is not None] for x in row]

List comprehension with else pass

How do I do the following in a list comprehension?
test = [["abc", 1],["bca",2]]
result = []
for x in test:
if x[0] =='abc':
result.append(x)
else:
pass
result
Out[125]: [['abc', 1]]
Try 1:
[x if (x[0] == 'abc') else pass for x in test]
File "<ipython-input-127-d0bbe1907880>", line 1
[x if (x[0] == 'abc') else pass for x in test]
^
SyntaxError: invalid syntax
Try 2:
[x if (x[0] == 'abc') else None for x in test]
Out[126]: [['abc', 1], None]
Try 3:
[x if (x[0] == 'abc') for x in test]
File "<ipython-input-122-a114a293661f>", line 1
[x if (x[0] == 'abc') for x in test]
^
SyntaxError: invalid syntax
The if needs to be at the end and you don't need the pass in the list comprehension. The item will only be added if the if condition is met, otherwise the element will be ignored, so the pass is implicitly implemented in the list comprehension syntax.
[x for x in test if x[0] == 'abc']
For completeness, the output of this statement is :
[['abc', 1]]
As a complement to Jaco's answer; it is nice to know about the filter command because what you basically want is filtering a list:
filter( lambda x: x[0]=='abc', test)
which returns:
a list in Python 2
a generator in Python3 (which may be useful for very long lists since you can later handle the result without overburdening the memory); if you still want a list, just wrap the filter function above with a list() constructor.
I added the if statement after the for loop and it worked for my use case.
data = [a for a in source_list if (your_condition)]

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

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]

Categories

Resources