How could this function be implemented without recursion? - python

I'm trying to do a bingo game, I had some struggle with it but finally sorted it out.
However, my main "problem" (more like, I've heard its bad programming) is that with my function I'm calling my function inside it in an else statement. I don't think that it's how you suppose to do it, i have not found any way around it though.. Because this function is called from another function called menu() so when i use a loop, it goes back to the menu if false.
Here's my code:
def selectingNumbers():
numbers = []
dupl = []
j = 0
print("Now you are gonna select 5 number\n")
while j < 5:
nummer = int(input("Your choice:\n"))
numbers.append(int(nummer))
j = j+1
for i in numbers:
if i not in dupl:
dupl.append(i) #New list without duplicates
if dupl == numbers: #Comparing new list with old list
print("No equal numbers found")
dragning(numbers)
else:
print("Equal numbers found")
selectingNumbers() #Is there a better way to do it?
I also had some issues with the list at the beginning, I know I can use the set() function but i want to keep the original list as it is and compare the new one with the old one, can I do that in a better way with "real" programming instead of import modules?
Hope you can answer or guide me on these two questions with alternatives and if so, say why my code is "bad" if it is.

Well you have to decide if you want to use recursion to solve the problem. This line is a recursive call:
selectingNumbers() #Is there a better way to do it?
Which is fine, and does not equate to bad programming. However, the rest of your function does no cater to a recursive function. You reset your variables and have no true base case because of that. See google, or here for examples.
Recursion is confusing for beginners, so I would take an iterative only approach. Here is a bingo python example.
In addition, I'm not sure this line works:
if dupl == numbers: #Comparing new list with old list
I am not too familiar with python, but in my experience, arrays are treated as objects, so in that line you would be asking python to compare two seperate objects with unique references in memory. So they will never be equal, even if the values inside of them are the same because they are both referenced seperately. I found this link to answer that concern.

Recursion isn't "bad". In fact it can sometimes greatly simplify a solution to a problem. However in the case of your code it isn't necessary. Fortunately, it can sometimes be replaced with a loop. In the case of your code it looks like it could just loop until it gets a list from the user that doesn't contain any duplicates. That means it could be rewritten as shown below (I also simplified a few other things):
def selectingNumbers():
while True:
print("Now you are gonna select 5 different numbers\n")
numbers = []
for _ in range(5):
number = int(input("Your choice:\n"))
numbers.append(number)
unique = set(numbers) # will remove any duplicates
if len(unique) == len(numbers): # no dups?
print("No equal numbers found")
break # <--- terminates loop
else:
print("Equal numbers found")
# allow loop to continue
dragning(numbers)

Related

Why is it wrong to put break as an expression in a list comprehension? [duplicate]

This question already has an answer here:
Creating a Python list comprehension with an if and break
(1 answer)
Closed 2 years ago.
I tried to write a program to keep asking for an integer input and append it in a list
until 0 is given, in which case I need to print the list that has been created so far and stop the program.
list1 = []
while True:
n = int(input('enter number: '))
[list1.append(n) if n!=0 else break]
print(list1)
This gives me a SyntaxError.
Why is that?
(I know I can do this without list comprehension but I'm just trying to understand why this is wrong.)
Please excuse any mistakes in my question as it is my first post
Edit: thank you everyone for your explanations. Now I have understood the reason for the error very well.
You need to use an if statement, not a conditional expression. The parameters in a conditional expression can only be expressions, not statements like break.
There's also no need to put the conditional inside a list.
while True:
n = int(input('enter number: '))
if n == 0:
break
else:
list1.append(n)
This is not one of the lines you want to save by using a ternary operator or whatever-comprehension. Just expand it:
while True:
n = int(input('enter number: '))
if n == 0:
break
list1.append(n)
The reason why you can't do it has been given in the comments: break is not a valid expression you can use in whatever-comprehensions or the ternary operator. Plus, you risk actually making the code less readable.
A list comprehension is NOT for one liners.
Its wrong because you're not comprehending a list, you're using it as a one line if statement. The break is not the only problem here, you're also appending to the list inside that "comprehension", not iterating over anything and then not assigning the comprehension result either.
What you've created is a list with a single element in it, which will be at best [None] since that is what append returns, but the break is a logical operator, not a value.
Instead, use an actual if statement and multiple readable lines
The break statement, like in C, breaks out of the innermost enclosing for or while loop.
From the python documentation
And if you take a look at the list display BNF notation, you will see, that it expects an expression, and not a statement.

When should I use a for loop or a while loop?

I am confused about when using a while-loop or for-loop is better? I am particularly worried about producing optimized answers to coding questions. I find myself solving problems just to find out a while-loop would've been faster but am confused about what leads people to choose to use it instead of a for-loop, like what criteria should I be looking for?
Here's an example of a coding question I answered which checks if a string of parentheses is balanced.
def parenCheck(str):
stack = Stack()
for x in str:
if x == '(':
stack.push(x)
else:
if stack.isEmpty():
return False
else:
stack.pop()
return stack.isEmpty()
Here is the answer I saw for it , which I know is faster because it doesnt use a for-loop:
def parChecker(symbolString):
s = Stack()
balanced = True
index = 0
while index < len(symbolString) and balanced:
symbol = symbolString[index]
if symbol == "(":
s.push(symbol)
else:
if s.isEmpty():
balanced = False
else:
s.pop()
index = index + 1
if balanced and s.isEmpty():
return True
else:
return False
For the same number of iterations, and content, my guess is that a for loop and wihile have practically the same speed. But I haven't tested that - mostly I answer numpy questions where we try to avoid either loop (preferring iterations in compiled code).
Your examples show the basic case where for results in cleaner, if not faster, code:
for x in an_iterator:
<do something>
versus
i = 0
while i < len(an_iterator):
x = an_iterator[x]
<do something>
i += 1
If you must have an index as well, you can use:
for i, x in enumerate(an_iterator):
....
That ability to iterate directly on things like lists and dictionaries was the main neat feature that caught my attention when I first saw Python in the 1990.
A common subcase of a for loop accumulates values, so common, that Python provides the popular list comprehension, and extended the syntax to generator expressions and dictionary comprehensions.
while still has its uses. Other languages have do while and do until variants, which attempt to streamline stepping the variable and testing. Python has just the one version with separate steps. The new walrus operator has the potential of cleaning that up:
https://docs.python.org/3/whatsnew/3.8.html#assignment-expressions
while (block := f.read(256)) != '':
process(block)
while is most useful when the steps aren't regular, or from a well defined iterator. for can break and continue, but otherwise the sequence is fixed (at the start of iteration).
In addition to enumerate, zip lets us iterate on several things at once.
The convenience of list comprehensions encourages us to decompose a complicated task into a sequence of comprehensions. And to make that even more convenient (and faster/memory efficient) Python provides generators and all sort so itertools. In Python 3, range and dictionary keys/items/values all became generator like expressions.
This cannot be decided by your code that while loop worked faster than for loop. As of your question on when to use while and for loop, it is decided on the basis of whether we know the number of iterations. If number of iterations is known, for loop is preferred, whereas while loop is preferred when the iterations are indefinite.
for (int i : mynumber_list)
Iterator it = mynumber_list.iterator()
while (it.hasNext())
As can be seen from above, for loop is more readable, simple, and easy in traversing. Moreover, iterator.hasNext() has a very high probability of entering into an infinite loop
while can also be useful for user choice input questions, like keep executing the program until the user presses any other key except y. This is difficult to achieve with for loop.

How to use Boolean variable as the if conditon in Python

I feel confused about the code as follows:
define this findmin function to find the smallest number in alist, O(n^2)
def findMin(alist):
overallmin=alist[0]
for i in alist:
issmallest=True
for j in alist:
if i>j:
issmallest=False
if issmallest:
overallmin = i
return overallmin
I can't understand: why the author set "issmallest = True" below the first for loop? Commonly when we feel like to use boolean values like this situation(such as assign boolean value to a variable at the beginning of the code or put the boolean values as the if-statement conditions)? Thanks!
Okay so first off, to erase a few of the mistakes in the code, a working example would be:
def findMin(alist):
overallmin=alist[0]
for i in alist:
issmallest=True
for j in alist:
if i>j:
issmallest=False
if issmallest:
overallmin = i
return overallmin
The idea behind this code is to compare all elements in a list with all others and keep the one that is smaller than all others. In the loop it is therefore assumed that the current element is the smallest issmallest = True until a smaller one is found. If a smaller one is found, the value of issmallest is changed to False. So if, after comparison with all others, issmallest is still True, then the element is truly the smallest and therefore fixed as such.
You could simplify this code , as there is no need in further comparing once the smallest element is found, i.e. you can leave the function. Also in this algorithm there is no need of keeping a variable for the smallest element. The corresponding code might read something like:
def findMin(alist):
for current_el in alist:
issmallest = True
for other_el in alist:
if other_el < current_el:
issmallest = False
if issmallest:
return current_el
But: Even for beginners, this is not a good code to find the minimum. I can say that as a beginner myself. It is much cleaner to go through the list once, with an element at hand, compare it while going through, and always keep the smallest.
So even with low afford you can write a much faster algorithm like this:
def findMin(alist):
smallest_el = alist.pop() # take out an element, no need to compare with itself
for other_el in alist:
if other_el < smallest_el:
smallest_el = other_el
return smallest_el
The condition of while always must evaluate to boolean. if it evaluates to true, the loop continues, otherwise, the statements after the loop will be executed. Please note: the code in your question did not involve a while loop. This code is very bad, please forget it, and everything that came with it. For learning, try this: https://www.learnpython.org/.

difference using recursive functions python

I have lists which consist of random letters..
def similarity(out_list):
i=0
count=0
while i<len(out_list):
if out_list[i][-1]==out_list[i+1][-1]:
count+=1
return similarity(out_list[i][:-1]) + count
elif out_list[i][-1]!=out_list[i+1][-1]:
return similarity(out_list[i][:-1])
i+=2
out_list=["ABABA","ACA","AGAGA","AAVA","XBX","ARAA","AADA","AAA","BABAB","ABA"]
similarity(out_list)
In my code I'm trying to find difference between list elements which are first and second, third and forth etc..
However since my function is recursive, the value of i is always 0 and I can't control other elements and I can't find the difference..
for ABABA and ACA the difference is 3 because first A and third A are the common in both words at same indexes.. so difference 5-2=3
what changes do my code require? Thank you.
Consider passing i as a parameter into your recursive function instead of setting it as 0 at the very start of the function. It's likely you would want to do something similar to count too.

Quick Sort using Python

I was wondering if someone can help me to fix the error my code for quick sort has:
It does not compile and highlights the last line of the code in red.
I can not figure out what is wrong. sort is already defined as a function so why is it highlighted as red?
def sort(*myarray):
less = []
equal = []
greater = []
if len(myarray) > 1:
pivot = myarray[0]
for x in myarray:
if x < pivot:
less.append(x)
if x == pivot:
equal.append(x)
if x > pivot:
greater.append(x)
return sort(less)+sort(equal)+sort(greater)
else:
return myarray
print sort([12,4,5,6,7,3,1,15])
You're defining the function as taking a variable number of arguments (the *myarray bit), but then using myarray inside as a single argument (the list to sort), when it is a list containing the list to sort.
You probably should remove the * from your function parameter. This questions esplains it quite thoroughly.
You could keep the *, but then you would have to play a bit with tuple unpacking to get the same result.
edit
Although the above is true, this might not be the issue you're encountering.
IDLE will give you the invalid syntax error on the ast line, because in interactive mode - with lines starting with >>>, it accepts only one statement at a time. In your case that statement is the sort() definition.
Try hitting enter 2 times after the function definition, this should get you back to the repl, where you can introduce another statement (print sort([12,4,5,6,7,3,1,15]))
There are a couple things wrong which makes me curious how you are testing this:
Python code is not "compiled", it is interpreted. (Okay, not precisely true; it's parsed into a sort of byte-code; still, it's not compiled in the same sense as a language such as C, where the entire program has to be converted into machine instructions before any of it can be run.) Also you mention the last line of code is highlighted in red -- by what?
This code actually works, but only if you remote the star/asterisk in front of myarray in def sort(*myarray):. Otherwise it actually returns a single-element tuple containing the original array.
Assuming you have two or more elements that equal a pivot at some point, you get an infinite loop, because you will get: equal = [x,x] (two elements at least), and then invoke sort([x,x]), which in its turn will take x as a pivot, and create equal = [x,x], and cause sort([x,x]), ....
Simple solution to this problem: What should be the output of the sort(equal)? How do you sort a list of identical elements?
Edit: Well, your comments show that you are looking for a different problem, but I'll leave it here because it explains a different issue you have with your code and should be solved.
If it is a function for quick sorting, can you really use the function sort in it?
Wouldn't something like this work?
def qsort(list):
pivind=0
left, right, pivot= [], [], []
for x in list:
if list[pivind]==x: pivot.append(x)
elif list[pivind]>x: left.append(x)
else: right.append(x)
if len(left)>1: left=qsort(left)
if len(right)>1: right=qsort(right)
return (left + pivot + right)

Categories

Resources