Replace functions with something iterable
In a nutshell. How do I write something else: for another in combinationOfK(K-1, L[i+1:]): My function combinationOfK(
…) is not iterative.
I’m trying to understand code in here, solution. Problem 26: Generate a combination of K different objects selected from N elements of the list
I know what yield does. But I’m trying to write code without the yield
statement. The code with yield statement is like this.
def combination(K, L):
if K<=0:
yield []
return
for i in range(len(L)):
thisone = L[i:i+1]
for another in combination(K-1, L[i+1:]):
yield thisone + another
The question, yield-keyword-explained
made me think I could replace yield. The receipt they provided didn’t work for me, yes:
When you see a function with
yield
statements, apply this easy
trick to understand what will happen:
- Insert a line
result = []
at the start of the function.- Replace each
yield expr
withresult.append(expr)
.- Insert a line
return result
at the bottom of the function.- Yay – no more
yield
statements! Read and figure out code.- Revert function to original definition.
Use it to get code without generating yield to give me this. Code does not work (functions are not iterative). What do I have to write to make this code run without yield?
def combinationOfK(K,L):
result = []
if K <= 0:
result.append([])
return
for i in range(len(L)):
thisone = L[i:i+1]
for another in combinationOfK(K-1, L[i+1:]): # the error
result.append(thisone + another)
return result
I’m using this code to test functionality
the_list = ['a','b','c','d','e']
print list(combinationOfK(2, the_list))
Throws an error TypeError: 'NoneType' object is not iterable
.
Solution
The problem is that your original code uses return
in an unusual way.
def combination(K, L):
if K<=0:
yield []
return # <--- hmmm
Most of the time you won’t see return
in the generator because you don’t need it very often. Usually, the generator just “drops” at the end; The interpreter reaches the end of the generator without encountering the return
statement, and then it knows to throw a StopIteration
.
In this case, the code writer inserts a return
declaration to “speed up” the process. When K <= 0
, there is no more work to do, so the generator can throw a StopIteration
— but without the return
declaration, it will enter a for
loop, producing incorrect results. In my opinion, a clearer approach would be something like this:
def combination(K, L):
if K<=0:
yield []
else:
for i in range(len(L)):
thisone = L[i:i+1]
for another in combination(K-1, L[i+1:]):
yield thisone + another
Now the conversion works as expected:
def combination2(K, L):
result = []
if K <= 0:
result.append([])
else:
for i in range(len(L)):
thisone = L[i:i + 1]
for another in combination2(K - 1, L[i + 1:]):
result.append(thisone + another)
return result