How to iterate a function n times until a certain outcome? - python

I need to iterate a function until a certain outcome is reached. There are actually three different outcomes that will need to stop the loop from running. However, I need the function to iterate over the naturals, so basically I don't want to limit my range. How would I go about doing this? I assume I need to make a for loop or a while loop of some sort, but I have limited Python experience. Any feedback would be greatly appreciated.

Have a look at the itertools module. Documentation here
itertools.count() will give you the naturals and will never run out. itertools.takewhile() will continue to consume a sequence until some specified function returns True.

index = 0
while True:
if end_conditions:
break
index += 1
A for loop is usually used to loop through items in an iterable, which tend to be bounded. This while True method indicates that the loop could theoretically loop forever. You can use an if statement to break the loop when you satisfy the conditions.

Related

Out of memory when use for loop to input parameter in recursive function Python

I have a recursive function:
def recursive_func(parameter1):
.....
if __name__ == "__main__":
list_parameter_input = [a,b,c,d,e]
for item in list_parameter_input:
recursive_func(item)
Note: my recursive_func is very complex but I'm sure it won't have any error.
The problem is when I input a parameter1 with a single item in list_parameter_input, it's fast and needs small memory. When I input a parameter1 using for loop, it's prolonged and makes out of memory.It's so weird.
I'm checked time when recursive_func complete with each value in list_parameter_input.
When input with not using for loop: recursive_func(a) need x time.
When input with using for loop: recursive_func(a) need more x time (10x,11x,...) but with b,c,d,e give a same time.
I don't know why it's happen but I'm really sure recursive_func(a) is very fast when I input a with not using for loop
I mean recursive_func(i) is probably recursive_func(item) as you're never using i anywhere.
But the real problem seems to be that you're running the entire loop for each recursion. So each element of the list starts a recursion where it loops through the entire list, not just the rest of the list but the entire list. And each of the element of that loop does the same so:
5 recursions for the elements in the list
5*5 recursions for the elements in the list in the recursions
5*5*5 recursions for the elements in the list in the recursions of the recursion
...
That soon leads to a stack overflow.
Maybe I misunderstand your description of the code (you are technically not providing a Minimal, Reproducible Example), but if the code looks like this:
def recursive_func(parameter1):
...
list_parameter_input = [a,b,c,d,e]
for item in list_parameter_input:
recursive_func(item)
... then you have an infinite loop.
I.e. Unless the list_parameter_input is modified (items are removed) you are not making progress.
Can you verify that you are actually making progress through the input parameters?

Most efficient way to determine if an element is in a list

So I have alist = [2,4,5,6,9,10], and b = 6. What is the more efficient way to determine if b is in alist?
(1)
if b in alist:
print " b is in alist"
(2)
def split_list(alist,b):
midpoint = len(alist)/2
if b<=alist[midpoint]:
alist =alist[:midpoint]:
split_list(alist,b)
else:
alist=alist[midPoint:]
split_list(alist,b)
I thought method number 1 is better because it is only one line of code, but I've read that method 2 is better because it searchs from middle of list rather than from the beginning the.
Actually the difference between the functions you have shown lies in the matter of time saving during execution. If you are sure that your list will always have more than 2 members then function 2 is better but not too much.
Here is how it works
Function 1
if b in alist:
print " b is in alist"
This will loop through all element in the list only looking for b and when it finds it makes it true but what if your list has 200 members times become sensitive for your program
Function 2
def split_list(alist,b):
midpoint = len(alist)/2
if b<=alist[midpoint]:
alist =alist[:midpoint]:
split_list(alist,b)
else:
alist=alist[midPoint:]
split_list(alist,b)
This does the same except now you are testing a condition first using that midpoint so as to know where might "b" be so as to save the task of looping through the whole list now you will loop half the time, Note:You will make sure that your list has much members may be more than 3 to be reasonable to do that remainder because it may make your logic easy and readable in the future. So in some way it has helped you but consider the fact that what if your list has 200 elements and you divide that by two will it be too helpful to divide it by two and use 100 loop?
No!It still take significant time!
My suggestion according to your case is that if you want to work with small lists your function 1 is better. But if you want to work with huge lists!! Here are some functions which will solve your problem will saving much of your time if you want the best performance for your program. This function uses some built in functions which does take small time to finish because of some list information are in already in memory
def is_inside(alist,b):
how_many=alist.count(b) #return the number of times x appears in the list
if how_many==0:
return False
else:
return True
#you can also modify the function in case you want to check if an element appears more than once!
But if you don't want it to say how many times an element appears and only one satisfy your need! This also another way of doing so using some built in functions for lists
def is_inside(alist,b):
try:
which_position=alist.index(b) #this methods throws an error if b is not in alist
return True
except Error:
return False
So life becomes simple when using built functions specifically for lists. You should consider reading how to use lists well when they long for performance of the programs stuffs like dequeue,stacks,queue,sets
Good source is the documentation itself Read here!
The expected way to find something in a list in python is using the in keyword. If you have a very large dataset, then you should use a data structure that is designed for efficient lookup, such as a set. Then you can still do a find via in.

making python code block with loop faster

Is there a way I can implement the code block below using map or list comprehension or any other faster way, keeping it functionally the same?
def name_check(names, n_val):
lower_names = names.lower()
for item in set(n_val):
if item in lower_names:
return True
return False
Any help here is appreciated
A simple implementation would be
return any(character in names_lower for character in n_val)
A naive guess at the complexity would be O(K*2*N) where K is the number of characters in names and N is the number of characters in n_val. We need one "loop" for the call to lower*, one for the inner comprehension, and one for any. Since any is a built-in function and we're using a generator expression, I would expect it to be faster than your manual loop, but as always, profile to be sure.
To be clear, any short-circuits, so that behaviour is preserved
Notes on Your Implementation
On using a set: Your intuition to use a set to reduce the number of checks is a good one (you could add it to my form above, also), but it's a trade-off. In the case that the first element short circuits, the extra call to set is an additional N steps to produce the set expression. In the case where you wind up checking each item, it will save you some time. It depends on your expected inputs. If n_val was originally an iterable, you've lost that benefit and allocated all the memory up front. If you control the input to the function, why not just recommend it's called using lists that don't have duplicates (i.e., call set() on its input), and leave the function general?
* #Neopolitan pointed out that names_lower = names.lower() should be called out of the loop, as your original implementation called it, else it may (will?) be called repeatedly in the generator expression

Iterate a certain number of times without storing the iteration number anywhere [duplicate]

This question already has answers here:
Is it possible to implement a Python for range loop without an iterator variable?
(15 answers)
Closed 5 years ago.
I was wondering if it is possible to perform a certain number of operations without storing the loop iteration number anywhere.
For instance, let's say I want to print two "hello" messages to the console. Right now I know I can do:
for i in range(2):
print "hello"
but then the i variable is going to take the values 0 and 1 (which I don't really need). Is there a way to achieve the same thing without storing those unwanted values anywhere?
Needless to say, using a variable is not a big deal at all... I'm just curious.
The idiom (shared by quite a few other languages) for an unused variable is a single underscore _. Code analysers typically won't complain about _ being unused, and programmers will instantly know it's a shortcut for i_dont_care_wtf_you_put_here. There is no way to iterate without having an item variable - as the Zen of Python puts it, "special cases aren't special enough to break the rules".
exec 'print "hello";' * 2
should work, but I'm kind of ashamed that I thought of it.
Update: Just thought of another one:
for _ in " "*10: print "hello"
Well I think the forloop you've provided in the question is about as good as it gets, but I want to point out that unused variables that have to be assigned can be assigned to the variable named _, a convention for "discarding" the value assigned. Though the _ reference will hold the value you gave it, code linters and other developers will understand you aren't using that reference. So here's an example:
for _ in range(2):
print('Hello')
Others have addressed the inability to completely avoid an iteration variable in a for loop, but there are options to reduce the work a tiny amount. range has to generate a whole bunch of numbers after all, which involves a tiny amount of work; if you want to avoid even that, you can use itertools.repeat to just get the same (ignored) value back over and over, which involves no creation/retrieval of different objects:
from itertools import repeat
for _ in repeat(None, 200): # Runs the loop 200 times
...
This will run faster in microbenchmarks than for _ in range(200):, but if the loop body does meaningful work, it's a drop in the bucket. And unlike multiplying some anonymous sequence for your loop iterable, repeat has only a trivial setup cost, with no memory overhead dependent on length.
Although I agree completely with delnan's answer, it's not impossible:
loop = range(NUM_ITERATIONS+1)
while loop.pop():
do_stuff()
Note, however, that this will not work for an arbitrary list: If the first value in the list (the last one popped) does not evaluate to False, you will get another iteration and an exception on the next pass: IndexError: pop from empty list. Also, your list (loop) will be empty after the loop.
Just for curiosity's sake. ;)
This will print 'hello' 3 times without storing i...
[print('hello') for i in range(3)]
Sorry, but in order to iterate over anything in any language, Python and English included, an index must be stored. Be it in a variable or not. Finding a way to obscure the fact that python is internally tracking the for loop won't change the fact that it is. I'd recommend just leaving it as is.
for word in ['hello'] * 2:
print word
It's not idiomatic Python, but neither is what you're trying to do.
You can simply do
print 2*'hello'

When to use "while" or "for" in Python

When I should use a while loop or a for loop in Python? It looks like people prefer using a for loop (for brevity?). Is there any specific situation which I should use one or the other? Is it a matter of personal preference? The code I have read so far made me think there are big differences between them.
Yes, there is a huge difference between while and for.
The for statement iterates through a collection or iterable object or generator function.
The while statement simply loops until a condition is False.
It isn't preference. It's a question of what your data structures are.
Often, we represent the values we want to process as a range (an actual list), or xrange (which generates the values) (Edit: In Python 3, range is now a generator and behaves like the old xrange function. xrange has been removed from Python 3). This gives us a data structure tailor-made for the for statement.
Generally, however, we have a ready-made collection: a set, tuple, list, map or even a string is already an iterable collection, so we simply use a for loop.
In a few cases, we might want some functional-programming processing done for us, in which case we can apply that transformation as part of iteration. The sorted and enumerate functions apply a transformation on an iterable that fits naturally with the for statement.
If you don't have a tidy data structure to iterate through, or you don't have a generator function that drives your processing, you must use while.
while is useful in scenarios where the break condition doesn't logically depend on any kind of sequence. For example, consider unpredictable interactions:
while user_is_sleeping():
wait()
Of course, you could write an appropriate iterator to encapsulate that action and make it accessible via for – but how would that serve readability?¹
In all other cases in Python, use for (or an appropriate higher-order function which encapsulate the loop).
¹ assuming the user_is_sleeping function returns False when false, the example code could be rewritten as the following for loop:
for _ in iter(user_is_sleeping, False):
wait()
The for is the more pythonic choice for iterating a list since it is simpler and easier to read.
For example this:
for i in range(11):
print i
is much simpler and easier to read than this:
i = 0
while i <= 10:
print i
i = i + 1
for loops is used
when you have definite itteration (the number of iterations is known).
Example of use:
Iterate through a loop with definite range: for i in range(23):.
Iterate through collections(string, list, set, tuple, dictionary): for book in books:.
while loop is an indefinite itteration that is used when a loop repeats
unkown number of times and end when some condition is met.
Note that in case of while loop the indented body of the loop should modify at least one variable in the test condition else the result is infinite loop.
Example of use:
The execution of the block of code require that the user enter specified input: while input == specified_input:.
When you have a condition with comparison operators: while count < limit and stop != False:.
Refrerences: For Loops Vs. While Loops, Udacity Data Science, Python.org.
First of all there are differences between the for loop in python and in other languages.
While in python it iterates over a list of values (eg: for value in [4,3,2,7]), in most other languages (C/C++, Java, PHP etc) it acts as a while loop, but easier to read.
For loops are generally used when the number of iterations is known (the length of an array for example), and while loops are used when you don't know how long it will take (for example the bubble sort algorithm which loops as long as the values aren't sorted)
Consider processing iterables. You can do it with a for loop:
for i in mylist:
print i
Or, you can do it with a while loop:
it = mylist.__iter__()
while True:
try:
print it.next()
except StopIteration:
break
Both of those blocks of code do fundamentally the same thing in fundamentally the same way. But the for loop hides the creation of the iterator and the handling of the StopIteration exception so that you don't need to deal with them yourself.
The only time I can think of that you'd use a while loop to handle an iterable would be if you needed to access the iterator directly for some reason, e.g. you needed to skip over items in the list under some circumstances.
For loops usually make it clearer what the iteration is doing. You can't always use them directly, but most of the times the iteration logic with the while loop can be wrapped inside a generator func. For example:
def path_to_root(node):
while node is not None:
yield node
node = node.parent
for parent in path_to_root(node):
...
Instead of
parent = node
while parent is not None:
...
parent = parent.parent
while loop is better for normal loops
for loop is much better than while loop while working with strings, like lists, strings etc.
If your data is dirty and it won't work with a for loop, you need to clean your data.
For me if your problem demands multiple pointers to be used to keep
track of some boundary I would always prefer While loop.
In other cases it's simply for loop.

Categories