Incorrect output when processing batch of inputs from file (converting pre-to-postfix)
Question:
I am having trouble writing my results into my output file. I’m trying to recursively convert from prefix to postfix. If I copy the input all at once separately, the output overwrites it. If there is a way that I could print a block of input followed by a block of output that would also work.
import sys
def isoperator(i): # check if the input is an operator
if i in ['$', '^', '*', '/', '+', '-']:
return True
else:
return False
def isoperandoroperator(i): # check if the input is an operand
if i.isalpha and i.isnumeric or isoperator(i):
return True
else:
return False
my_list = sys.argv[1]
my_output = sys.argv[2]
def recursivepretopost(input): # method to convert from pre to postfix, takes input file as argument
char = input.read(1)
if char == 'n':
return ''
if char == ' ':
return ''
if isoperator(char): # if the character is an operator, perform recursive call to check the next character
return recursivepretopost(input) + recursivepretopost(input) + char
else: # if the character is an operand, return the operand
return char
with open(my_list, 'r') as file, open(my_output, 'w') as i: # use file to refer to the file object and open output file
for d in file:
i.write('Input: ' + d)
i.write('Output: ')
i.write(recursivepretopost(file) + 'n')
Here is the input of prefix expressions:
-+ABC
-A+BC
$+-ABC+D-EF
-*A$B+C-DE*EF
**A+BC+C-BA
/A+BC +C*BA
*-*-ABC+BA
/+/A-BC-BA
*$A+BC+C-BA
//A+B0-C+BA
*$A^BC+C-BA
This is my output:
Input: -+ABC
Output: ABC+-
Input:
Output: AB-C+DEF-+$
Input:
Output: ABCDE-+$*EF*-
Input:
Output: ABC+*CBA-+*
Input:
Output: ABC+/
Input: +C*BA
Output: AB-C*BA+-*
Input:
Output: ABC-/BA-+/
Input:
Output: ABC+$CBA-+*
Input:
Output: AB0+/CBA+-/
Input:
Output: ABC^$CBA-+*
But this is the intended output:
Input: -+ABC
Output: AB+C-
Input: -A+BC
Output: ABC+-
Input: $+-ABC+D-EF
Output: $+-ABC+D-EF
Input: -*A$B+C-DE*EF
Output: ABCDE-+$*EF*-
Input: **A+BC+C-BA
Output: ABC+*CBA-+*
Input: /A+BC +C*BA
Output: ABC+/
Input: *-*-ABC+BA
Output: AB-C*BA+-*
Input: /+/A-BC-BA
Output: ABC-/BA-+/
Input: *$A+BC+C-BA
Output: ABC+$CBA-+*
Input: //A+B0-C+BA
Output: AB0+/CBA+-/
Input: *$A^BC+C-BA
Output: ABC^$CBA-+*
Answers:
The problem isn’t in how you’re writing to your output file, it’s in how you’re reading from your input file. Your for
loop iterates through the open file, line by line. You then also call that file’s read
method, which advances the current position in the file, which screws up your loop. This is essentially the same problem as the classic "Don’t remove items from a list while you’re iterating through it" gotcha.
The simplest way to fix your existing recursive function would be to create a StringIO
instance of each string you wish to process. A StringIO supports reading as if it were a file, even though it’s simply a string stored in memory.
Other things I changed:
- Gave variables more descriptive names, and put function names in snake_case
- Changed function comments to docstrings
- Stripped each line of left and right whitespace, including
n
, and removed spaces, so that you don’t need to handle those within your function
- Simplified how
is_operator
returns its boolean, and checked membership in a set rather than a list
- Removed unused
isoperandoroperator
- Used f-strings for formatting output
from io import StringIO
import sys
def is_operator(char):
"""Check if the input is an operator."""
return char in {'$', '^', '*', '/', '+', '-'}
def recursive_pre_to_post(stream):
"""Convert from pre to postfix.
Takes input file or string buffer as argument
"""
char = stream.read(1)
if is_operator(char):
# If the character is an operator, perform recursive call to
# check the next character.
return (recursive_pre_to_post(stream) +
recursive_pre_to_post(stream) +
char)
else:
# If the character is an operand, return the operand.
return char
in_name = sys.argv[1]
out_name = sys.argv[2]
with open(in_name) as in_file, open(out_name, 'w') as out_file:
for line in in_file:
line = line.strip().replace(' ', '')
out_file.write(f'Input: {line}n')
result = recursive_pre_to_post(StringIO(line))
out_file.write(f'Output: {result}n')
I am having trouble writing my results into my output file. I’m trying to recursively convert from prefix to postfix. If I copy the input all at once separately, the output overwrites it. If there is a way that I could print a block of input followed by a block of output that would also work.
import sys
def isoperator(i): # check if the input is an operator
if i in ['$', '^', '*', '/', '+', '-']:
return True
else:
return False
def isoperandoroperator(i): # check if the input is an operand
if i.isalpha and i.isnumeric or isoperator(i):
return True
else:
return False
my_list = sys.argv[1]
my_output = sys.argv[2]
def recursivepretopost(input): # method to convert from pre to postfix, takes input file as argument
char = input.read(1)
if char == 'n':
return ''
if char == ' ':
return ''
if isoperator(char): # if the character is an operator, perform recursive call to check the next character
return recursivepretopost(input) + recursivepretopost(input) + char
else: # if the character is an operand, return the operand
return char
with open(my_list, 'r') as file, open(my_output, 'w') as i: # use file to refer to the file object and open output file
for d in file:
i.write('Input: ' + d)
i.write('Output: ')
i.write(recursivepretopost(file) + 'n')
Here is the input of prefix expressions:
-+ABC
-A+BC
$+-ABC+D-EF
-*A$B+C-DE*EF
**A+BC+C-BA
/A+BC +C*BA
*-*-ABC+BA
/+/A-BC-BA
*$A+BC+C-BA
//A+B0-C+BA
*$A^BC+C-BA
This is my output:
Input: -+ABC
Output: ABC+-
Input:
Output: AB-C+DEF-+$
Input:
Output: ABCDE-+$*EF*-
Input:
Output: ABC+*CBA-+*
Input:
Output: ABC+/
Input: +C*BA
Output: AB-C*BA+-*
Input:
Output: ABC-/BA-+/
Input:
Output: ABC+$CBA-+*
Input:
Output: AB0+/CBA+-/
Input:
Output: ABC^$CBA-+*
But this is the intended output:
Input: -+ABC
Output: AB+C-
Input: -A+BC
Output: ABC+-
Input: $+-ABC+D-EF
Output: $+-ABC+D-EF
Input: -*A$B+C-DE*EF
Output: ABCDE-+$*EF*-
Input: **A+BC+C-BA
Output: ABC+*CBA-+*
Input: /A+BC +C*BA
Output: ABC+/
Input: *-*-ABC+BA
Output: AB-C*BA+-*
Input: /+/A-BC-BA
Output: ABC-/BA-+/
Input: *$A+BC+C-BA
Output: ABC+$CBA-+*
Input: //A+B0-C+BA
Output: AB0+/CBA+-/
Input: *$A^BC+C-BA
Output: ABC^$CBA-+*
The problem isn’t in how you’re writing to your output file, it’s in how you’re reading from your input file. Your for
loop iterates through the open file, line by line. You then also call that file’s read
method, which advances the current position in the file, which screws up your loop. This is essentially the same problem as the classic "Don’t remove items from a list while you’re iterating through it" gotcha.
The simplest way to fix your existing recursive function would be to create a StringIO
instance of each string you wish to process. A StringIO supports reading as if it were a file, even though it’s simply a string stored in memory.
Other things I changed:
- Gave variables more descriptive names, and put function names in snake_case
- Changed function comments to docstrings
- Stripped each line of left and right whitespace, including
n
, and removed spaces, so that you don’t need to handle those within your function - Simplified how
is_operator
returns its boolean, and checked membership in a set rather than a list - Removed unused
isoperandoroperator
- Used f-strings for formatting output
from io import StringIO
import sys
def is_operator(char):
"""Check if the input is an operator."""
return char in {'$', '^', '*', '/', '+', '-'}
def recursive_pre_to_post(stream):
"""Convert from pre to postfix.
Takes input file or string buffer as argument
"""
char = stream.read(1)
if is_operator(char):
# If the character is an operator, perform recursive call to
# check the next character.
return (recursive_pre_to_post(stream) +
recursive_pre_to_post(stream) +
char)
else:
# If the character is an operand, return the operand.
return char
in_name = sys.argv[1]
out_name = sys.argv[2]
with open(in_name) as in_file, open(out_name, 'w') as out_file:
for line in in_file:
line = line.strip().replace(' ', '')
out_file.write(f'Input: {line}n')
result = recursive_pre_to_post(StringIO(line))
out_file.write(f'Output: {result}n')