I've created a function named number(x) that tests a number to see whether or not a number is perfect or not. Now my goal is to create a tester function that tests all numbers from 1 to 1000 and return numbers that are perfect. This is the code i have for the test function:
def unittest():
for i in range(0,1000):
perfect(i)
if True:
return i
It's not working, but i think i'm close. Any advice or help?
I think you meant this, and notice the correct parameters for range, and how we use a list to accumulate all the results - otherwise, the function will return only one value!
def unittest():
ans = []
for i in range(1, 1001):
if perfect(i):
ans.append(i)
return ans
Alternatively, and not recommended (it's redundant), you could test if the returned value was True:
def unittest():
ans = []
for i in range(1, 1001):
if perfect(i) is True :
ans.append(i)
return ans
Yet another alternative would be to use list comprehensions, which is more idiomatic and potentially faster than using an explicit loop:
def unittest():
return [i for i in range(1, 1001) if perfect(i)]
When you return, that's the end of your function. If you want to return all of the perfect numbers, you have to keep track of them and return them all at the end.
On top of that, your if True: means you'll return 0 whether it's perfect or not.
So, what you need to do is:
def unittest():
results = []
for i in range(1000):
if perfect(i):
results.append(i)
return results
There actually is a way to solve this without building the list, by using yield instead of return. That's probably too advanced for you to learn right now, but I'll explain it anyway. First, here's the code:
def unittest():
for i in range(1000):
if perfect(i):
yield i
See the tutorial section on Iterators, and the following two sections, for details. But basically, a yield is like a return that doesn't return. What your function actually returns is not a list, but a generator. If someone then iterates over that generator, it will go through your function until the first yield, then go through until the next yield, and so on until you're done. The tutorial explains this much better than a single paragraph ever could.
Related
I've written a function to create combinations of inputs of an arbitrary length, so recursion seemed to be the obvious way to do it. While it's OK for a small toy example to return a list of the results, I'd like to yield them instead. I've read about yield from, but don't fully understand how it is used, the examples don't appear to cover my use case, and hoping'n'poking it into my code has not yet produced anything that works. Note that writing this recursive code was at the limit of my python ability, hence the copious debug print statements.
This is the working list return code, with my hopeful non-working yield commented out.
def allposs(elements, output_length):
"""
return all zero insertion paddings of elements up to output_length maintaining order
elements - an iterable of length >= 1
output_length >= len(elements)
for instance allposs((3,1), 4) returns
[[3,1,0,0], [3,0,1,0], [3,0,0,1], [0,3,1,0], [0,3,0,1], [0,0,3,1]]
"""
output_list = []
def place_nth_element(nth, start_at, output_so_far):
# print('entering place_nth_element with nth =', nth,
# ', start_at =', start_at,
# ', output_so_far =', output_so_far)
last_pos = output_length - len(elements) + nth
# print('iterating over range',start_at, 'to', last_pos+1)
for pos in range(start_at, last_pos+1):
output = list(output_so_far)
# print('placing', elements[nth], 'at position', pos)
output[pos] = elements[nth]
if nth == len(elements)-1:
# print('appending output', output)
output_list.append(output)
# yield output
else:
# print('making recursive call')
place_nth_element(nth+1, pos+1, output)
place_nth_element(0, 0, [0]*output_length)
return output_list
if __name__=='__main__':
for q in allposs((3,1), 4):
print(q)
What is the syntax to use yield from to get my list generated a combination at a time?
Recursive generators are a powerful tool and I'm glad you're putting in the effort to study them.
What is the syntax to use yield from to get my list generated a combination at a time?
You put yield from in front of the expression from which results should be yielded; in your case, the recursive call. Thus: yield from place_nth_element(nth+1, pos+1, output). The idea is that each result from the recursively-called generator is iterated over (behind the scenes) and yielded at this point in the process.
Note that for this to work:
You need to yield the individual results at the base level of the recursion
To "collect" the results from the resulting generator, you need to iterate over the result from the top-level call. Fortunately, iteration is built-in in a lot of places; for example, you can just call list and it will iterate for you.
Rather than nesting the recursive generator inside a wrapper function, I prefer to write it as a separate helper function. Since there is no longer a need to access output_list from the recursion, there is no need to form a closure; and flat is better than nested as they say. This does, however, mean that we need to pass elements through the recursion. We don't need to pass output_length because we can recompute it (the length of output_so_far is constant across the recursion).
Also, I find it's helpful, when doing these sorts of algorithms, to think as functionally as possible (in the paradigm sense - i.e., avoid side effects and mutability, and proceed by creating new objects). You had a workable approach using list to make copies (although it is clearer to use the .copy method), but I think there's a cleaner way, as shown below.
All this advice leads us to:
def place_nth_element(elements, nth, start_at, output_so_far):
last_pos = len(output_so_far) - len(elements) + nth
for pos in range(start_at, last_pos+1):
output = output_so_far[:pos] + (elements[nth],) + output_so_far[pos+1:]
if nth == len(elements)-1:
yield output
else:
yield from place_nth_element(elements, nth+1, pos+1, output)
def allposs(elements, output_length):
return list(place_nth_element(elements, 0, 0, (0,)*output_length))
HOWEVER, I would not solve the problem that way - because the standard library already offers a neat solution: we can find the itertools.combinations of indices where a value should go, and then insert them. Now that we no longer have to think recursively, we can go ahead and mutate values :)
from itertools import combinations
def place_values(positions, values, size):
result = [0] * size
for position, value in zip(positions, values):
result[position] = value
return tuple(result)
def possibilities(values, size):
return [
place_values(positions, values, size)
for positions in combinations(range(size), len(values))
]
I want to write a function friend(my_class, n) that return a list of people who have minimum n friends, return an empty list if no person has at least n friends.
This my code, can someone tell me what i did wrong?
my_class = [[1,2,3],[0,3],[0,4],[0,1],[2]]
def friend(my_class,n):
for j in range(len(my_class)):
if my_class[j][n] >= n:
return my_class[j]
return ([])
because when i call:
friend(my_class, 2)
it returns [1,2,3] instead of [0,1,2,3]
This is basic debugging, which you need to learn to do for yourself.
my_class = [[1,2,3],[0,3],[0,4],[0,1],[2]]
def friend(my_class,n):
for j in range(len(my_class)):
if my_class[j][n] >= n:
return my_class[j]
return ([])
friend(my_class, 2) will enter a for loop. In the case where j is 0, we look at my_class[0] and there are 3 friends. Because 3>2 we immediately return. Once the function executes a return, it is DONE. It will not continue in the for loop.
You found the adjacency list for the first node which has at least 2 friends, and that's what you returned. I can't go any further without doing your homework for you, but in answer to your question, "What did you do wrong?" you executed return (on the wrong data) before the function was done.
I need help creating a list of iterated values. In this example, I want to get all odd numbers in the range of x. Then make a list from it:
def x_list(x):
for i in range(x):
if x%2==0:
return i
Since return stops the function after iterating through the first object, I'm unable to get the rest of the values and create a list from it.
Could you advice what I should use instead of "return"?
Thank you.
If you use yield instead of return, then you should be able to iterate through the whole range. This example will print out the even numbers.
def x_list(x):
for i in range(x):
if i%2==1:
yield i
for n in x_list(10):
print(n)
I also assume you want if i%2==1: not if x%2==0:, otherwise you'll get every number instead of just the odd ones.
Based on hop's suggestion, you could also do this:
evens = range(0, 10, 2)
for n in evens:
print(n)
Where the 3rd parameter in range is the step size
Define ret as a list at the top of the function, fill it within the loop.
After the loop ends, return it.
def x_list(x):
ret = []
for i in range(x):
if i%2==0:
ret.append(i)
return ret
With range, you can specify a stepping.
Therefore, all you need to do is:
def oddlist(x):
return list(range(1, x, 2))
If you don't actually need a list, and just an iterable will do, you could omit the list generation:
def oddlist(x):
return range(1, x, 2)
Here's my python code
def search(myList, number):
for i in myList:
if i[0] == number:
return i[1]
return None
myList = [(5107261, 'Ernst'), (6524256, 'Arvo')]
number = 5107261
print(search(myList, number))
Now I want to write it using recursion but I'm not sure how to do it. I need some pointers to help me get started.
When writing recursive code, you want to define a base case, and you want to define a method for making your problem smaller on every step. In this example, we are working with lists, so a good base case would be an empty list, []. If the list is empty, it makes sense to return None. In your recursive case, you want to do some work to make the problem smaller. In this case we can check one element, and if that element is not what we are searching for, we can call the function again on a smaller version of the list.
Our result is a function like this:
def searchR(myList, number):
if length(myList) == 0: return None
elif myList[0][0] == number: return myList[0][1]
else: return searchR(myList[1:], number)
There are 3 cases. Case 1 is our base case, where the length of the list is 0. Case 2 is our success case, where we found the the target of the search. Case 3 is where we make our recursive call. Notice how the first element is removed from the new list! If the first element isn't removed, the function will loop forever.
For example, the below code
primeList = []
for val in range(2, num):
if not any(val % i == 0 for i in primeList):
primeList.append(val)
How can I turn this exact piece of code into list comprehension?
No, you can't, because the list doesn't exist as a Python object until the comprehension is finished iterating. You can't reference an object that doesn't exist. Honestly, I would just leave this as a for loop - list comprehensions aren't a magic bullet to replace all list-constructing loops.
However... you can get tricky and use a generator, which is only evaluated on demand. Combining this with the extend() method of a list, which adds elements to the list as it obtains them (in my tests, anyway), you can use the current contents of the list you're extending as you extend it.
# make sure to set `num`
plist = []
plist.extend(c for c in range(2, num) if not any(c % p == 0 for p in plist))
Fair warning: as far as I know, the fact that extend() adds elements to the list as it produces them is not part of the specification, so whether this bit of code works could be implementation-dependent. But I tested it in Python 2.7 and 3.4 and got a list of primes each time.
Actually, if you really really want to, you can create an identical copy of the list within the list comprehension and refer to that...
primeListCopy = []
primeList = [primeListCopy.append(val) or val for val in range(2, num)
if not any(val % i == 0 for i in primeListCopy)]
This uses the fact that primeListCopy.append(val) or val evaluates to val, because assignment to list returns None and or evaluates to the right side value.
This is definitely worse performance-wise than a simple for-loop. I wrote this in response to OP's question "what could be the closest mimic when i had nothing but list comprehension. ( this is not a development code, just my experiments)"
That said, the additional work only adds O(n) of work so doesn't actually increase the algorithmic complexity of the loop. It's conceivable (though not very likely) that the list comprehension optimization will make this faster than the original for-loop.
#!/usr/bin/python
from __future__ import print_function
import math
def is_prime(x):
if (x == 0 or x == 1 or x < 0):
return False
for i in range(2, int(math.sqrt(x)) + 1):
if (not (x % i)):
return False
return True
def filter_primes(max):
return [val for val in range(2, max) if is_prime(val)]
def main():
primes = filter_primes(20)
print(primes)
if __name__ == "__main__":
main()
The code above starts with defining a function called is_prime(x) which returns True if x is a prime number, False otherwise. Then a function called filter_primes(max) uses is_prime with list comprehension to filter the prime numbers into an array that's returned. The maximum number of the range is specified via max. The main function just invokes the API to test it out.
EDIT:
But maybe I've misunderstood what you meant by "turn this exact piece of code into list comprehension". Depending on what you really want to do, using a generator is a great idea for dynamic purposes.