Retr0spect Retr0spect - 5 months ago 16
Python Question

Python: How to write this python one-liner in 'readable' way?

I have started to learn Python. I very confused with one-liner used in this code (5th line in the below code).

Can someone please explain to me how this one liner is working? May be re-write in verbose way?

multiset = [2, 2, 3, 3, 4, 5, 6, 7, 8, 10]
x = [0]
deltaSet = set(multiset)

for candidate in deltaSet:
if sum([(abs(candidate-member) in multiset) for member in x]) == len(x):
for member in x:
multiset.remove(abs(candidate-member))
x.append(candidate)
if len(x) == n: break


Thanks!

Answer

I believe the line you are looking at is:

sum([(abs(candidate-member) in multiset) for member in x])

First, there are far too many parenthesis there. Lets get rid of the stuff we don't need:

sum(abs(candidate-member) in multiset for member in x)

Phew, that's a little better already. Now lets actually look at the expression piece by piece:

abs(candidate - member) in multiset

This is self explanatory enough ... Is the absolute value of the candidate minus the member in the multiset? If yes, the expression returns True, if not, the expression returns False. Now what are the member? Well, there's one for each thing in the iterable x. So you're summing a bunch of True and False. In python, booleans are subclassed from int (with True == 1 and False == 0), the sum is basically counting the number of times that expression we talked about earlier is True.

Then they check if it is equal to the len(x) so basically, the code is checking if the expression is True for every member in x. Fortunately, there's a better way to write this in python:

all(abs(candidate - member) in multiset for member in x)

If this is still confusing, we could rewrite this as a function (lets call it f(x):

def f(x):
    """Equivalent to `all(abs(candidate - member) in multiset for member in x."""
    for member in x:
        if not abs(candidate - member) in multiset:
            return False
    return True

For some reference reading, in both cases, I've used generator expressions (which are similar to list-comprehensions in syntax and meaning, but they generate the items "yielded" on the fly rather than materializing an entire list at once. They're more memory efficient and faster for some operations. They're particularly useful for cases where you don't need to look at every item to know the result (e.g. this one where a single False is enough to make the entire expression False).