GoTo(basic) program - python

I'm doing some tutorials online, and I'm stuck with an exercise :Write a function getBASIC() which takes no arguments, and does the following: it should keep reading lines from input using a while loop; when it reaches the end it should return the whole program in the form of a list of strings. Example of list of strings:
5 GOTO 30
10 GOTO 20
20 GOTO 10
30 GOTO 40
40 END
I wrote a program, but it doesn't work, however I will post it too:
def getBASIC():
L=[]
while "END" not in L:
L.append(str(input()))
if str(input()).endswith("END"):
break
return L
Also I notice you that I'm not allowed to use IS or RECURSION .

There are several errors:
you call input() twice without appending it to the list the second time
'END' in L determines whether there is 'END' (whole) line in the list L (there isn't)
Note: input()already returns a str object; you don't need to call str() on its returned value.
To read input until you've got empty line you could:
def getBASIC():
return list(iter(input, ''))
Or to read until END is encountered at the end of line:
def getBASIC():
L = []
while True:
line = input()
L.append(line)
if line.endswith("END"):
break #NOTE: it doesn't break even if `line` is empty
return L

Back when I was learning Pascal, we used a priming read for loops that needed at least one iteration. This still works well in Python (I prefer it to a while True / break loop).
By simply testing the last line in the list (rather than the last line read) we eliminate the need for a variable to store the input and can combine the reading and appending operations.
def getBASIC():
lines = [input("]")] # use Applesoft BASIC prompt :-)
while not lines[-1].upper().rstrip().endswith("END"):
lines.append(input("]"))
return lines

try this one:
def get_basic():
L = []
while True:
line = str( input() )
L.append( line )
if "END" in line:
break
return L

Use raw_input() instead of input(). input() function takes string from standard input and tries to execute it as a python source coode. raw_input() will return a string as expected.
You use input() 2 time inside a loop. That means you await two string to be input inside one cycle iteration. You don't need last condition (if statement) inside your while loop. It'll end up when "END" is encountered in L.
The next code should do the job:
def getBASIC():
L=[]
while True:
inp = raw_input()
L.append(inp)
if inp.endswith('END'):
break
return L

Your code has the following problems.
"while "END" not in L" will not work if your input is "40 END"
In Python 2.7, "input()" is equivalent to "eval(raw_input()))". So, Python is trying to evaluate the "GOTO" statements.
"if str(input()).endswith("END"):" does not append input to L
So, here is an updated version of your function:
def getBASIC():
L = []
while True:
# Grab input
L.append(str(raw_input()))
# Check if last input ends with "END"
if L[-1].endswith("END"):
break
return L

Related

Using generator to collate user inputs on multiple lines

I am trying to save some memory here - I am building a program where the user can input a (stacked) list of integers like:
1
2
3
4
5
.
.
.
The below code works good!
input_list = []
while True:
try:
line = input()
except EOFError:
break
input_list.append(int(line))
print(input_list)
But I would now like to use some sort of generator expression to evaluate the list only when I need, and I almost (argh!) got there.
This code works:
def prompt_user():
while True:
try:
line = input()
except EOFError:
print(line)
break
yield line
input_list = (int(line) for line in prompt_user())
print(list(input_list))
with one only quack: the last integer input by the user is always omitted. So for instance (the ^D is me typing CTRL+D at the console from a pycharm debugger):
1
2
3
4^D
3 # ==> seems like after the EOF was detected the integer on the same
# line got completely discarded
[1, 2, 3]
I don't really know how to go further.
Thanks to #chepner and to this other thread I reduced this whole logic to:
import sys
N = input() # input returns the first element in our stacked input.
input_list = map(int, [N] + sys.stdin.readlines())
print(list(input_list))
leveraging the fact that sys.stdin is already iterable!

How to add strings with each other during a loop?

For my programming class, I need to a create a program that takes in a string and two letters as an argument. Whenever the first letter appears in the string, it is replaced with the second letter. I can do this by making the final string into a list. However, our professor has stated that he wants it to be a string, not a list. The code shown below is what I used to make the program work if the final result was to appear in a list.
def str_translate_101(string, x, y):
new_list = []
for i in string:
if i == x:
new_list.append(y)
if i != x:
new_list.append(i)
return new_list
I tried to make one where it would output a string, but it would only return the first letter and the program would stop (which I'm assuming happens because of the "return")
def str_translate_101(string, old, new):
for i in string:
if i == old:
return new
else:
return i
I then tried using the print function, but that didn't help either, as nothing was outputted when I ran the function.
def str_translate_101(string, old, new):
for i in string:
if i == old:
print(new)
else:
print(i)
Any help would be appreciated.
An example of how the result should work when it works is like this:
str_translate_101('abcdcba', 'a', 'x') ---> 'xbcdcbx'
You can use join to merge a list into a string:
def str_translate_101(string, x, y):
new_list = []
for i in string:
if i == x:
new_list.append(y)
else:
new_list.append(i)
return ''.join(new_list)
or use the one-liner
str_tranlsate_101 = str.replace
The simplest solution would be, instead of storing the character in a list you can simply declare an empty string and in the 'if' block append the character to the string using the augmented '+=' operator. E.g.
if i == x:
concat_str += y
As for the return, basically, it will break out of the for loop and return to where the function was called from. This is because it only has 1 objective, which once achieved it will not bother to process any further code and simply go back to where the function was called from.

Python 3 Index Error

Consider the following code:
def anadist(string1, string2):
string1_list = []
string2_list = []
for i in range(len(string1)):
string1_list.append(string1[i])
for i in range(len(string2)):
string2_list.append(string2[i])
# Test returns for checking
# return (string1_list,string2_list)
# return len(string1_list)
# return len(string2_list)
for i in range(0,len(string1_list)):
try:
if (string1_list[i]) in string2_list:
com = string1_list.pop(i)
com_index = string2_list.index(com)
string2_list.pop(com_index)
else:
pass
except ValueError:
pass
return string1_list
def main():
str1 = input("Enter string #1 >>> ")
str2 = input("Enter string #2 >>> ")
result = anadist(str1, str2)
print(result)
#Boilerplate Check
if __name__ == "__main__":
main()
Running in Python 3.5.2 raises an IndexError:
Traceback (most recent call last):
File "E:\CSE107L\Practice\anadist.py", line 34, in <module>
main()
File "E:\CSE107L\Practice\anadist.py", line 29, in main
result = anadist(str1, str2)
File "E:\CSE107L\Practice\anadist.py", line 15, in anadist
if (string1_list[i]) in string2_list:
IndexError: list index out of range
And I can't find what is going wrong. I wrote another code similar and that works:
def main():
lst = [1,2,3,4,5]
lst2 = [5,6,7,8,9]
for i in range(len(lst)):
if lst[i] in lst2:
com = lst.pop(i)
lst2_index = lst2.index(com)
lst2.pop(lst2_index)
else:
pass
print(lst)
if __name__ == "__main__":
main()
I feel the error is coming from the way I am forming string1_list. This code is for how many steps it takes to form an anagram of a pair of words.
In some cases, you are shortening string_list1 while you're iterating over it:
if (string1_list[i]) in string2_list:
com = string1_list.pop(i) # string1_list gets shorter here
However, your range doesn't change. It's still going to go from 0 until it counts up to the original length of string1_list (exclusive). This will cause the IndexError any time string1_list.pop(i) is called.
One possible solution would be to use a while loop instead:
i = 0
while i < len(string1_list):
try:
if string1_list[i] in string2_list:
com = string1_list.pop(i)
com_index = string2_list.index(com)
string2_list.pop(com_index)
else:
pass
except ValueError:
pass
i += 1
This will cause the loop termination condition to be checked after each iteration. If you remove some elements from string1_list, it'll still be OK because the loop will terminate before i gets big enough to overrun the bounds of it's container.
Your issue is that you are mutating the string1_list within the for loop by performing string1_list.pop(i). The length of the list is being reduced within the for loop by doing string1_list.pop(i), but you are still iterating over the length of the original list.
Your second lot of code works only because you only pop on the last iteration of the loop.
Your second attempt works simply because a "match" is found only in the last element 5 and as such when you mutate your list lst it is during the last iteration and has no effect.
The problem with your first attempt is that you might remove from the beginning of the list. The counter doesn't get updated and at some point might reach a value that no longer exists in the list (it has been popped). Try running it with no matches in the input and see that it works.
In general, don't mutate your list while iterating through it. Instead of the:
for i in range(len(lst)):
# mutate list
'idiom', you should opt for the:
for i in list(list_object): # or for i in list_object[:]:
which makes a copy first and allows you to mutate the original list_object by keeping mutating and looping separate.

Python 'for' function

I am trying to write a code that returns every prime palindrome with three digits. Here is my code:
def digpalprim():
for x in range (100,1000):
if prime(x)=='prime':
if str(x)==str(x)[::1]:
return x
I've already defined the prime(x) function, it works well, that stage just determines whether x is prime or not. All in all the code works, except that it only gives me the first such a palindrome. I don't really understand why, shouldn't the program consider all the numbers between 100 and 1000? Please help?
Your function returns as soon as it finds the first such palindrome; return exits a function.
Collect your finds in a list and return that:
def digpalprim():
palindromes = []
for x in range (100,1000):
if prime(x)=='prime':
if str(x)==str(x)[::1]:
palindromes.append(x)
return palindromes
or you can make your function a generator by replacing the return with a yield statement:
def digpalprim():
for x in range (100,1000):
if prime(x)=='prime':
if str(x)==str(x)[::1]:
yield x
Now you'll have to iterate over this function or use list() to 'pull' all values out:
all_palindromes(digpalprim())
or
for palindrome in digpalprim():
print(palindrome)
You are returning the function the first time you encounter one.
def digpalprim():
palprimes = []
for x in range (100,1000):
if prime(x)=='prime':
if str(x)==str(x)[::1]:
palprimes.append(x)
return palprimes
This creates a list at the start of the function and appends each valid palindrome prime to that list, then returns the entire list (after completing all loops) instead of returning just the first one encountered.
Just remember, if Python hits a return statement, it's going to stop function execution right there and return that value regardless of any additional loops or code you may intend to be executed.
The function returns and ends as soon as the first result is found.
You may wish to add the results to a list and then print out the list.
return x This statement causes the program to return to the calling function once this statement is encountered. To return all you may put it in an list. For e.g:
you can have a list called values and append it to it, and finally return it at the end
For such small tasks, I prefer using list comprehensions:
palindromes = [x for x in range(100, 1000) if (prime(x) == 'prime') and (str(x) == str(x)[::1])]
Or (equivalently):
condition = lambda f: prime(f) == 'prime' and str(f) == str(f)[::1]
palindromes = [x for x in range(100, 1000) if condition(x)]

any way to loop iteration with same item in python?

It's a common programming task to loop iteration while not receiving next item. For example:
for sLine in oFile :
if ... some logic ... :
sLine = oFile.next()
... some more logic ...
# at this point i want to continue iteration but without
# getting next item from oFile. How can this be done in python?
I first thought you wanted the continue keyword, but that would of course get you the next line of input.
I think I'm stumped. When looping over the lines of a file, what exactly should happen if you continued the loop without getting a new line?
Do you want to inspect the line again? If so, I suggest adding an inner loop that runs until you're "done" with the input line, which you can then break out of, or use maybe the while-condition and a flag variable to terminate.
Simply create an iterator of your own that lets you push data back on the front of the stream so that you can give the loop a line that you want to see over again:
next_lines = []
def prependIterator(i):
while True:
if next_lines:
yield(next_lines.pop())
else:
yield(i.next())
for sLine in prependIterator(oFile):
if ... some logic ... :
sLine = oFile.next()
... some more logic ...
# put the line back so that it gets read
# again as we head back up to the "for
# statement
next_lines.append(sLine)
If the prepend_list is never touched, then the prependIterator behaves exactly like whatever iterator it is passed: the if statement inside will always get False and it will just yield up everything in the iterator it has been passed. But if items are placed on the prepend_list at any point during the iteration, then those will be yielded first instead before it returns back to reading from the main iterator.
What you need is a simple, deterministic finite state machine. Something like this...
state = 1
for sLine in oFile:
if state == 1:
if ... some logic ... :
state = 2
elif state == 2:
if ... some logic ... :
state = 1
Ugly. Wrap the body in another loop.
for sLine in oFile :
while 1:
if ... some logic ... :
sLine = oFile.next()
... some more logic ...
continue
... some more logic ...
break
A little better:
class pushback_iter(object):
def __init__(self,iterable):
self.iterator = iter(iterable)
self.buffer = []
def next(self):
if self.buffer:
return self.buffer.pop()
else:
return self.iterator.next()
def __iter__(self):
return self
def push(self,item):
self.buffer.append(item)
it_file = pushback_iter(file)
for sLine in it_file:
if ... some logic ... :
sLine = it_file.next()
... some more logic ...
it_file.push(sLine)
continue
... some more logic ...
Unfortunately no simple way of referencing the current iterator.
Instead of looping through the file line by line, you can do a file.readlines() into a list. Then loop through the list (which allows you to look at the next item if you want). Example:
list = oFile.readlines()
for i in range(len(list))
#your stuff
list[i] #current line
list[i-1] #previous line
list[i+1] #next line
you can go to the previous or next line by simply using [i-1] or [i+1]. You just need to make sure that no matter what, i does not go out of range.
You just need to create a variable out of your iterator, and then manipulate that:
% cat /tmp/alt-lines.py
#! /usr/bin/python -tt
import sys
lines = iter(open(sys.argv[1]))
for line in lines:
print line,
lines.next()
% cat /tmp/test
1
2
3
4
% /tmp/alt-lines.py /tmp/test
1
3
...note that in this case we unconditionally do lines.next() so the above fails for files with odd lines, but I assume that isn't going to be the case for you (and adding the error checking is fairly trivial -- just catch and throw away StopIteration on the manual .next()).
You can assign your iterator to an variable then use the .next get te next one.
iter = oFile.xreadlines() # is this the correct iterator you want?
try:
sLine = iter.next()
while True:
if ... some logic ... :
sLine = iter.next()
... some more logic ...
continue
sLine = iter.next()
except StopIterator:
pass
jle's approach should work, though you might as well use enumerate():
for linenr, line in enumerate(oFile):
# your stuff

Categories

Resources