-2

What's the one liner for the below code?

for k,v in d2.items():
    if d1.get(k,0) < v:
        return False
return True

I tried this but it's invalid syntax.

return False if d1.get(k,0)<v for k,v in d2.items() else True

Why?

wjandrea
  • 28,235
  • 9
  • 60
  • 81

3 Answers3

6

Use any or all:

return not any(d1.get(k, 0) < v for k, v in d2.items())

or

return all(d1.get(k, 0) >= v for k, v in d2.items())
wjandrea
  • 28,235
  • 9
  • 60
  • 81
1
return False if any([d1.get(k,0)<v for k,v in d2.items()]) else True
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • 2
    This technically works, but it's much more verbose than necessary and fails to short-circuit. – user2357112 Jun 27 '20 at 03:03
  • 3
    The list is unnecessary and worsens the performance. Also the ternary statement is pointless when you could just use `not`. `return not any(d1.get(k, 0) < v for k, v in d2.items())` – wjandrea Jun 27 '20 at 03:07
  • Sadly yes, It does not do early termination. I'm wondering is there any better one liner here. – Lutfar Rahman Milu Jun 27 '20 at 03:12
  • 1
    Don't use a list comprehension, use a generator expression, `any` does short circuit, but that's defeated if you create the whole list up front – juanpa.arrivillaga Jun 27 '20 at 03:33
-1

TL;DR

Most efficient

Use wjandrea solution

(It is not memory efficient) Not good looking

return False if [True for k, v in d2.items() if d1.get(k, 0) < v] else True

(It is not memory efficient) Better

return not [True for k, v in d2.items() if d1.get(k, 0) < v]

Explanation

Your code is not syntactically correct because the return statement needs one or more expressions. So, the for statement is not an expression and that's why it fails.

In the code above I wrote a list comprehension, which is an expression, because at the end it is a list.

Then, I make an if to the list (which in fact checks the length of the list, and if it is empty it will be a 0, which is considered False, while any other number is considered True).

The second code, which does not have the if statement, has the not operator, which does the check described earlier with the if and then returns a boolean.

I hope this explains why that happened, which was your second question.

And also, this post is responding to your main question and not asking why you want it to be one liner. I would prefer to use the multiline version you posted, so you don't store any values and break instantly.

EDIT

I would prefer to use the multiline version you posted, so you don't store any values and break instantly.

Reading wjandrea correct solution, I correct myself, with any you don't have to store any value, it returns True immediately after it finds a True value, so it is as efficient as the multiline version.

gorandp
  • 500
  • 5
  • 11
  • 2
    This fails to short-circuit, builds a big unnecessary list, and is less clear than using `any` or `all`. – user2357112 Jun 27 '20 at 06:11
  • 1
    I like your explanation, but some details are off: 1) `for` in this context makes a [comprehension](https://docs.python.org/3/reference/expressions.html#grammar-token-comp-for), not a statement, but yes it's not an expression. 2) `if` in this context makes a [conditional expression](https://docs.python.org/3/reference/expressions.html#grammar-token-conditional-expression) (AKA ternary), not a statement. 3) Using `if` on a list is more like `bool(list)` than `bool(len(list))`, since empty lists are falsy themselves, and this is abstracted away to an extent, but yes they're equivalent. – wjandrea Jun 27 '20 at 19:16
  • Yes [user2357112 supports Monica](https://stackoverflow.com/questions/62605333/one-liner-for-dictionary-comparison-in-python/62605730#comment110714872_62605730) you are right, that's why I pointed the [wjandrea](https://stackoverflow.com/a/62605444/12692806) solution to be more efficient than mine. I agree that the use of `any` or `all` is more clear. – gorandp Jun 27 '20 at 21:56