You don't need any conditional expression* here, as str.split() always returns a list, even if only containing one word:
lst[:] = [word for words in lst for word in words.split()]
Demo:
>>> lst = ['word','word','multiple words','word']
>>> [word for words in lst for word in words.split()]
['word', 'word', 'multiple', 'words', 'word']
The conditional expression can be used wherever you could use a simple expression in the syntax; that means anywhere it says expression or old_expression in the list display grammar:
list_display ::= "[" [expression_list | list_comprehension] "]"
list_comprehension ::= expression list_for
list_for ::= "for" target_list "in" old_expression_list [list_iter]
old_expression_list ::= old_expression [("," old_expression)+ [","]]
old_expression ::= or_test | old_lambda_expr
list_iter ::= list_for | list_if
list_if ::= "if" old_expression [list_iter]
So the first part of a list comprehension, but also the part that produces the outermost iterator (evaluated once), the if expressions, or any of the nested iterators (evaluated each iteration of the next outer for loop).
*It's called the conditional expression; it is a ternary operator, but so is the SQL BETWEEN operator.
You don't need any conditional expression* here, as str.split() always returns a list, even if only containing one word:
lst[:] = [word for words in lst for word in words.split()]
Demo:
>>> lst = ['word','word','multiple words','word']
>>> [word for words in lst for word in words.split()]
['word', 'word', 'multiple', 'words', 'word']
The conditional expression can be used wherever you could use a simple expression in the syntax; that means anywhere it says expression or old_expression in the list display grammar:
list_display ::= "[" [expression_list | list_comprehension] "]"
list_comprehension ::= expression list_for
list_for ::= "for" target_list "in" old_expression_list [list_iter]
old_expression_list ::= old_expression [("," old_expression)+ [","]]
old_expression ::= or_test | old_lambda_expr
list_iter ::= list_for | list_if
list_if ::= "if" old_expression [list_iter]
So the first part of a list comprehension, but also the part that produces the outermost iterator (evaluated once), the if expressions, or any of the nested iterators (evaluated each iteration of the next outer for loop).
*It's called the conditional expression; it is a ternary operator, but so is the SQL BETWEEN operator.
First of all, you have the order wrong. To use the ternary operator, you have to do it like this:
[a if c else b for item in list]
That being said, you cannot really have another list comprehension level embedded depending on some condition. The number of levels has to be fixed.
As you are just looking to split for whitespace, you can just perform this anyway though, as splitting a string without whitespace will still give you back a list with a single item back:
[subword for word in list for subword in word.split()]
Videos
Put your variables in a dictionary instead, and then you can vary the key you are assigning to:
names = {'stuart': 0, 'kevin': 0}
for itr, char in enumerate(word_list):
names['kevin' if char in "aeiou" else 'stuart'] += len(word_list) - itr
You can't otherwise use a conditional expression to switch out variables.
It is not possible to change the variable on left-hand side of assignment. However you can use the globals() trick to assign to a global variable, though this is frowned upon, thus never do this:
stuart = 0
kevin = 0
globs = globals()
for itr, char in enumerate(word_list):
globs['kevin' if char in 'aeiou' else 'stuart'] += len(word_list) - itr
For most perfomant code, one can gather the counts in a list of 2 items, and index them by char in "aeiou" which will choose index 1 (because True == 1!) for vowels and index 0 (as False == 0) for consonants; then unpack these to desired variables. Also, the length of word_list will be constant, but since Python cannot know this, the code will perform better if len(word_list) is placed outside the loop:
counts = [0, 0]
length = len(word_list)
for itr, char in enumerate(word_list):
counts[char in "aeiou"] += length - itr
stuart, kevin = counts
I think this is the most idiomatic way to write the code:
def array_count9(nums):
return sum(num == 9 for num in nums)
But you could also do this if you want to use the if/else construct:
def array_count9(nums):
return sum(1 if num == 9 else 0 for num in nums)
The blueprint for a ternary operator is:
condition_is_true if condition else condition_is_false
The statement where the syntax error occurs is at
count += 1 if i == 9 else pass for i in nums
ie count += 1 does not meet the blueprint specification, because condition_is_true should not need to be evaluated.
1 if A else 2 if B else 3 translates to this:
def myexpr(A, B):
if A:
return 1
else:
if B:
return 2
else:
return 3
Your ternary expression can be interpreted with parentheses as follows:
(
(1 if A) else (
(2 if B) else 3
)
)
Could someone please explain why this is executed in this order, and possibly suggest some material that gives an intuition about why this is used/preferred?
I'm trying to answer the "intuition" part of your question by solving a simple but more general problem.
'''
+-----------------------------------------------------------------------------------+
| Problem: |
+-----------------------------------------------------------------------------------+
| Convert a |
| nested if-else block into |
| a single line of code by using Pythons ternary expression. |
| In simple terms convert: |
| |
| 1.f_nested_if_else(*args) ( which uses |
| ```````````````````` nested if-else's) |
| | |
| +--->to its equivalent---+ |
| | |
| V |
| 2.f_nested_ternary(*args) ( which uses |
| ``````````````````` nested ternary expression) |
+-----------------------------------------------------------------------------------+
'''
'''
Note:
C:Conditions (C, C1, C2)
E:Expressions (E11, E12, E21, E22)
Let all Conditions, Expressions be some mathematical function of args passed to the function
'''
#-----------------------------------------------------------------------------------+
#| 1. | Using nested if-else |
#-----------------------------------------------------------------------------------+
def f_nested_if_else(*args):
if(C):
if(C1):
return E11
else:
return E12
else:
if(C2):
return E21
else:
return E22
#-----------------------------------------------------------------------------------+
#| 2. | Using nested ternary expression |
#-----------------------------------------------------------------------------------+
def f_nested_ternary(*args):
return ( (E11) if(C1)else (E12) ) if(C)else ( (E21) if(C2)else (E22) )
#-----------------------------------------------------------------------------------+
#-----------------------------------------------------------------------------------|
#-----------------------------------------------------------------------------------|
#-----------------------------------------------------------------------------------|
#-----------------------------------------------------------------------------------+
Here is a visualization of why f_nested_if_else() and f_nested_ternary() are equivalent.
# +-----------------------------------------------------------------------------+
# | Visualization: |
# +-----------------------------------------------------------------------------+
# | Visualize the ternary expression like a binary tree : |
# | -Starting from the root and moving down to the leaves. |
# | -All the internal nodes being conditions. |
# | -All the leaves being expressions. |
# +-----------------------------------------------------------------------------+
_________________
|f_nested_ternary|
``````````````````
( (E11) if(C1)else (E12) ) if(C)else ( (E21) if(C2)else (E22) )
| | | | | | |
| | | | | | |
V V V V V V V
Level-1| +----------------(C)-----------------+
-------- True/ __________________ \False
V |f_nested_if_else| V
Level-2| +----(C1)----+ `````````````````` +----(C2)----+
-------- True/ \False True/ \False
V V V V
Level-3| ( (E11) (E12) ) ( (E21) (E22) )
------------------------------------------------------------------------------------+
Hope this visualization gave you an intuition of how nested ternary expressions are evaluated :P
You have to use a generator expression for that:
return next((x2 for x, x2 in opts if x == "--config"), str())
The expression (x2 for x, x2 in opts if x == 1) is a generator: it
can be used to iterate over a set of elements. For instance:
opts = [(1, 2), (1, 3), (2, 4)]
gen = (x2 for x, x2 in opts if x == 1)
for x in gen:
print(x) # print 2 and 3
next returns the next element of the generator (or the first if you
have not generated any element for now).
If the generator does not contain any next element, then the second
(optional) argument of next is returned. Otherwise an exception is raised. For instance:
opts = [(1, 2), (2, 3)]
gen = (x2 for x, x2 in opts if x == 4)
x = next(gen) # raise StopIteration
gen = (x2 for x, x2 in opts if x == 4)
x = next(gen, 5)
print(x) # print 5
So to summarise, return next((x2 for x, x2 in opts if x == "--config"), str()) is equivalent to your for loop: using your generator you take the first element x, x2 of opts such that x == "--config" and return x2 ; and if there is no such element you return str()
There are a few pieces to this.
The fallback return of str() will always give '' as you are asking it for the string value of literally nothing. If that's what you want you might as well return '' instead.
Unless all of your opts are 2-tuples (or other iterables with 2 elements each), then anything singleton opt will fail at for x, x2 in opts. At a guess, you are more likely feeding a list of strings to this function, examples being
opt_config(['--config', 'elderberries', 'castle']) -> 'elderberries'
opt_config(['grail', 'swallow', '--config', 'rabbit']) -> 'rabbit'
opt_config(['parrot', 'cheese', 'Olympics']) -> ''
Again, speculating on what you want, it appears you want either the first config option given (and only the first), or '' if '--config' never shows up.
If my interpretations of your intentions are correct, then something like this might be what you want for the 'non-ternary' version of the code:
def opt_config(opts):
if '--config' in opts:
ndx = opts.index('--config')
if ndx < len(opts):
return opts[ndx + 1]
return ''
opt_config(['--config', 'elderberries', 'castle'])
'elderberries'
opt_config(['grail', 'swallow', '--config', 'rabbit'])
'rabbit'
opt_config(['parrot', 'cheese', 'Olympics'])
''
If you want to compress that code down you can take it all the way to a 1-liner using the ternary operator you asked about:
opt_config2 = lambda opts: opts[opts.index('--config') + 1] if '--config' in opts[:-1] else ''
opt_config2(['--config', 'elderberries', 'castle'])
'elderberries'
opt_config2(['grail', 'swallow', '--config', 'rabbit'])
'rabbit'
opt_config2(['parrot', 'cheese', 'Olympics'])
''
With the ternary operator x if y else z, the if y part is evaluated first, so python efficiently calculates only one of the x and z options as required.