7

I am trying to pass each element of foo_list into a function expensive_call, and get a list of all the items whose output of expensive_call is Truthy. I am trying to do it with list comprehensions, is it possible? Something like:

Something like this:

 result_list = [y := expensive_call(x) for x in foo_list if y]

or....

 result_list = [y for x in foo_list if y := expensive_call(x)]

Note: This is not a solution because it call expensive call twice:

 result_list = [expensive_call(x) for x in foo_list if expensive_call(x)]

And before someone recommends none list comprehension, I know one can do:

result_list = []
for x in foo_list:
   result = expensive_call(x)
   result and result_list.append(result)
8
  • 5
    "a list of all the items whose output of expensive_call is Truthy." Wait, doesn't that mean you want the result to contain original elements from the input? Isn't that just [x for x in foo_list if expensive_call(x)]? What's the difficulty? (That corresponds to the code in your non-comprehension version, too.) Commented Jan 18, 2022 at 18:37
  • 3
    What is wrong with your second version? Did you try it? Commented Jan 18, 2022 at 18:38
  • 3
    How about: [y for y in map(expensive_call,foo_list) if y] Commented Jan 18, 2022 at 18:40
  • 3
    In your loop version, avoid cutesy things like result and result_list.append(x), use if result: result_list.append(x), idiomatic Python values clarity and being explicit, not brevity Commented Jan 18, 2022 at 18:41
  • 1
    You might want to edit your loop variation, because it is different logic than the others. You clearly wanted the last line: result and result_list.append(result). Though as @juanpa.arrivillaga says, that's "cutesy" and could mislead many. Commented Jan 18, 2022 at 18:48

3 Answers 3

9

Quoting from above:

result_list = [y for x in foo_list if y := expensive_call(x)]

It should work almost exactly as how you have it; just remember to parenthesize the assignment with the := operator, as shown below.

foo_list = [1, 2, 3]
def check(x): return x if x != 2 else None

result_list = [y for x in foo_list if (y := check(x))]
print(result_list)

Result:

[1, 3]
Sign up to request clarification or add additional context in comments.

4 Comments

Does it fail without the parentheses?
Yep, definitely seems to fail for me; at least when I test with a Python 3.9 environment.
Interesting. I wonder how it parses.
From the PEP on the walrus operator, it looks like there are edge cases where the () are required around the expression; tbh I'm not sure why it's needed here though.
2

As suggested by RufusVS, this works and has the expected complexity.

def expensive_call(x):
    return x == 5

foo_list = [1,2,3,4,5,6,6,5]
print([y for y in map(expensive_call,foo_list) if y])

results in

[True, True]

As there are two 5 that satisfy expensive_call

Comments

1

You want to check if expensive_call(x) is Truthy, and if so append it to the list? Something like this should work. Doesn't need to use a walrus op:

[x for x in foo_list if expensive_call(x)]

If you want to store the output of expensive_call(x) and not x then your second approach needs parentheses around the walrus assignment due to how the assignment operator works. Refer to PEP 572 for more info.

[y for x in foo_list if (y := expensive_call(x))]

4 Comments

The OP wants to save the result of the call, not the argument. AFAICT
@RufusVS if you refer to OP's non-comprehension they use result_list.append(x) not result_list.append(result) and they said they want to store the item if the output of the func is truthy not store the ouput of the func if it's truthy.
I did not even read the loop version he posted. Clearly it's not the same logic as his other attempts, but now I see where you were coming from.
Sorry for causing confusion, I corrected my code, thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.