简体   繁体   中英

What is the difference between these two codes of Python subset recursion function?

def all_subsets(s):
    if len(s) == 1: return [[], s]
    else:
        sets = all_subsets(s[:-1])
        for e in sets:
            return sets + [e + [s[-1]]]

I've tried the above code and it only returns [[], [1], [2], [3]]

So I've accidentally tried the one liner return statement as below:

def all_subsets(s):
    if len(s) == 1: return [[], s]
    else:
        sets = all_subsets(s[:-1])
        return sets + [e + [s[-1]] for e in sets]

And it worked. I can't understand how using for loop in the return statement makes this code work; PLEASE help me understand how it's working, because I've tried running it on the visualizer, and I still don't understand.

AND if you can be so kind as to make my FIRST code work without using the one liner return statement, if it is possible.

A MILLION GRATITUDES IN ADVANCE

The first case fails to return the result you expected because of the return statement inside the for loop. Basically the code will exit the function in the first iteration of the for loop (summing only the first subset and then returning the result and ending the function call)... The second example sums all the subsets and then returns the result.

The problem in your first case is that it returns the first time in the for loop. For the first e, it returns and then gets out of the loop. To fix your code:

def all_subsets(s):
    if len(s) == 1: return [[], s]
    else:
        sets = all_subsets(s[:-1])
        returnset = []
        for e in sets:
            returnset.extend([e,e + [s[-1]]])
        return returnset

s= [1,2,3]
print all_subsets(s)

[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]

I would prefer the list comprehension version though.

Apart from the question about your code, here's a way to get a list of all subsets:

(from: https://wiki.python.org/moin/Powerful%20Python%20One-Liners )

Here's a working function to return a list of all subsets of any given sequence:

#!/python
f = lambda l: reduce(lambda z, x: z + [y + [x] for y in z], l, [[]])

... notice that this lambda is defined recursively (just as in your functions).

Also it's worth nothing that the size of the set of subsets grows as 2**n for n elements. In other words for a set of 10 elements the set of subsets has 1024 elements.

What way of thinking of this and modeling it is to consider the all of the binary numbers from 0 to 2**n ... if you enumerate all such bit strings and consider each to be a "mask" of which items to include in the corresponding subset then you'll find that you've covered all possible subsets from the empty set (0) through the full original set (11111...1111).

One implication of this is that you can return the "nth" "subset" of a sequence without enumerating all the intervening "subsets" (scare quotes because, mathematically a set is unordered; but this handling depends on mapping bit strings to a sequence ... on the "set" being treated in an orderly).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM