'Python transform and filter list with for / if
Is there a way to both transform and filter in a single list comprehension, i.e.:
def transform(el):
if some_condition(el):
return None
return complex_logic(el)
def main():
transformed = [transform(el) for el in some_list if transform(el) != None]
but avoid calling transform
twice? I.e. assign it to a variable, something like (in pseudo-Python):
def main():
transformed = [transformed for el in some_list let transformed = transform(el) if transformed != None]
Solution 1:[1]
Since Python 3.8 you can use walrus operator :=
:
def main():
return [res for el in some_list if (res := transform(el)) is not None]
This way the result of calling to the transform
function is stored in res
then you can use it in the expression part of your list comprehension.
Solution 2:[2]
Replace let transformed = transform(el)
with for transformed in [transform(el)]
.
Solution 3:[3]
I would approach the solution from simple, over idiomatic to readable:
Simple loop with temp var
The simple but verbose for-loop can be used to "cache" the transformation result in a temporary variable t
:
def transform(el):
if some_condition(el):
return None
return complex_logic(el)
def main():
transformed_list = []
for el in some_list:
t = transform(el) # invoked once
if t is not None: # equivalent to `if transform(el) != None`
transformed_list.append(t)
Embedded List Comprehension
Like Kelly Bundy suggests, embed the list-comprehensions:
- transformation of elements
- filter for non-null
See also Temporary variable within list comprehension
Decouple condition from transformation
Command–query separation (CQS) can be applied
to have a simplifying effect on a program, making its states (via queries) and state changes (via commands) more comprehensible.
Assume the 2 given functions (some_condition
and complex_logic
) were separately defined because each implements a single-responsibility (SRP). Then it would be consequential to take advantage of this separation and reuse the 2 steps in suitable composition:
- Query: by
filter
first using the condition function as predicate - Command: afterwards to transform by complex logic
This way the pipeline or stream might even become more readable:
transformed = [complex_logic(el) for el in filter(some_condition, some_list)]
Finally this is close to what Samwise advised in his comment: Now the SRP is followed.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | hc_dev |
Solution 2 | Kelly Bundy |
Solution 3 |