Python File reading and writing - python

I'm currently coding a program that is supposed to:
1) Open a file which has names along with grades on each line
(I have successfully done this and put the contents of each line into an array).
2) Evaluate the data and find the max, min, and average.
I am stuck in the second part because if I try to use the max or min function pertaining to the array, I have an error code that pops up, since the values in the array are technically a string.
So my question is how do I only get the value of the numbers? Would a parallel list be more useful and if so how would I implement that?
Here's my code so far:
def getGrades(filename):
try:
gradeArray = []
with open("Grades.txt", "r") as f:
for line in f:
gradeArray.append(line.find())
except:
print("Could not open", filename)
return(gradeArray)

Optimize as needed:
minValue = 0
maxValue = 0
total = 0
first = int(gradeArray[0])
total = first
for i in range(1, len(gradeArray)):
minValue = min(first, int(gradeArray[i]))
maxValue = max(first, int(gradeArray[i]))
total = total + int(gradeArray[i])
average = total / len(gradeArray)

Related

Python continue for loop from file

I have a code that generates characters from 000000000000 to ffffffffffff which are written to a file.
I'm trying to implement a check to see if the program was closed so that I can read from the file, let's say at 00000000781B, and continue for-loop from the file.
The Variable "attempt" in (for attempt in to_attempt:) has tuple type and always starting from zero.
Is it possible to continue the for-loop from the specified value?
import itertools
f = open("G:/empty/last.txt", "r")
lines = f.readlines()
rand_string = str(lines[0])
f.close()
letters = '0123456789ABCDEF'
print(rand_string)
for length in range(1, 20):
to_attempt = itertools.product(letters, repeat=length)
for attempt in to_attempt:
gen_string = rand_string[length:] + ''.join(attempt)
print(gen_string)
You have to store the value on a file to keep track of what value was last being read from. I'm assuming the main for loop running from 000000000000 to ffffffffffff is the to_attempt one. All you need store the value of the for loop in a file. You can use a new variable to keep track of it.
try:
with open('save.txt','r') as reader:
save = int(reader.read())
except FileNotFoundError:
save = 0
#rest of the code
for i in range(save,len(to_attempt)):
with open('save.txt','r') as writer:
writer.write(i)
#rest of the code

How do I make sure all of my values are computed in my loop?

I am working on a 'keep the change assignment' where I round the purchases to the whole dollar and add the change to the savings account. However, the loop is not going through all of the values in my external text file. It only computes the last value. I tried splitting the file but it gives me an error. What might be the issue? my external text file is as so:
10.90
13.59
12.99
(each on different lines)
def main():
account1 = BankAccount()
file1 = open("data.txt","r+") # reading the file, + indicated read and write
s = 0 # to keep track of the new savings
for n in file1:
n = float(n) #lets python know that the values are floats and not a string
z= math.ceil(n) #rounds up to the whole digit
amount = float(z-n) # subtract the rounded sum with actaul total to get change
print(" Saved $",round(amount,2), "on this purchase",file = file1)
s = amount + s
x = (account1.makeSavings(s))
I'm fairly sure the reason for this is because you are printing the amount of money you have saved to the file. In general, you don't want to alter the length of an object you are iterating over because it can cause problems.
account1 = BankAccount()
file1 = open("data.txt","r+") # reading the file, + indicated read and write
s = 0 # to keep track of the new savings
amount_saved = []
for n in file1:
n = float(n) #lets python know that the values are floats and not a string
z= math.ceil(n) #rounds up to the whole digit
amount = float(z-n) # subtract the rounded sum with actaul total to get change
amount_saved.append(round(amount,2))
s = amount + s
x = (account1.makeSavings(s))
for n in amount_saved:
print(" Saved $",round(amount,2), "on this purchase",file = file1)
This will print the amounts you have saved at the end of the file after you are finished iterating through it.

Using a generator in a while loop and evaluate after every yield

I'm using Python to open some files in a CAD program. Since the program will crash when I open too many files at once, I want my script to stop opening files from a list I generated when the sum of thier filesize exceeds a certain value.
Here is what I have so far:
I'm converting the log file to a list. It contains the filepaths seperated by commas:
fList = []
with open('C:/Users/user/Desktop/log.txt', 'r') as f:
fList = f.read().split(',')
with suppress(ValueError, AttributeError):
fList.remove('')
fcount = len(fList)
This is the Generator that I use to Iterate over the partList:
def partGenerator(partList):
for file in partList:
yield file
Here I try to loop over the files while the sum of thier size is smaller than 2500000 bite:
count = 0
progression = 0
storage = 0
while storage < 2500000:
for file in partGenerator(fList):
name = os.path.basename(file)
storage += os.path.getsize(file)
print(f'Auslastung: {storage} bite / 2500000 bite')
oDoc = oApp.Documents.Open(file)
progression += 1
percent = round(100 * progression / fcount)
print(f'Fortschritt: {progression} / {fcount} ({percent} %) - {name}')
What happens is, that the files open propperly in the CAD Software, but they don't stop after the while condition is exceeded. My guess is, that the while condition is evaluated after the list runs out of entries and not after every entry like I what to.
Help on the correct syntax would be great!
What I'm looking for ultimately:
I would like to use this script in a way that it opens some files and whenever I manualy close one in the CAD program, It opens the next one from my list until the list is exhausted.
Your while condition is never checked, no, because the for loop never lets Python check. That the for loop takes elements from a generator function is neither here nor there.
You need to check inside your for loop if your condition still holds:
for file in partGenerator(fList):
name = os.path.basename(file)
storage += os.path.getsize(file)
if storage >= 2500000:
# wait for input before continuing, then reset the storage amount
input("Please close some files to continue, then press ENTER")
storage = 0
Python doesn't check while conditions until the full suite (series of statements) in the block under the while ...: statement has completed running or executes a continue statement, so a while condition really isn't suitable here.
In the above example I used the low-tech input() function to ask whomever is running the script to press ENTER afterwards. It'll depend on what oDoc.Documents actually offers as an API to see if you could use that to detect that files have been closed.
If you wanted to use a generator function, have it track file sizes. You can even have it read those from the CSV file. I'd use the csv module to handle splitting and progress, by the way:
import csv
def parts(logfile):
with open(logfile, newline='') as f:
reader = csv.reader(f)
files = [column for row in reader for column in row if column]
fcount = len(files)
storage = 0
for i, filename in enumerate(files):
storage += os.path.getsize(file)
if storage >= 2500000:
input("Please close some files to continue, then press ENTER")
storage = 0
print(f'Auslastung: {storage} bite / 2500000 bite')
yield file
print(f'Fortschritt: {i} / {fcount} ({i / fcount:.2%}) - {name}')
then just use
for file in parts('C:/Users/user/Desktop/log.txt'):
oDoc = oApp.Documents.Open(file)
Note that the absolute number of files open is what your OS limits on, not how large those files are.
With the input from Martijn Pieters I came up with something that works perfectly for me. I'm a noob in programming so it took me a while to understand the problem. Here is what woked just fine in the end:
fList = []
with open('C:/Users/jhoefler/Desktop/log.txt', 'r') as f:
fList = f.read().split(',')
with suppress(ValueError, AttributeError):
fList.remove('')
fcount = len(fList)
count = 0
progression = 0
for file in fList:
name = os.path.basename(file)
if oApp.Documents.Count < 10:
oDoc = oApp.Documents.Open(file)
else:
pCount = oApp.Documents.LoadedCount
fCount = oApp.Documents.LoadedCount
while fCount == pCount:
time.sleep(1)
pCount = oApp.Documents.LoadedCount
oDoc = oApp.Documents.Open(file)
progression += 1
percent = round(100 * progression / fcount)
print(f'Fortschritt: {progression} / {fcount} ({percent} %) - {name}')
I'm sure there is a more elegant way to solve the problem, but it workes for my needs just fine.

Python: Generate ranged numbers and output the result to a file with a newline after each value appended

So what I am trying to do is to generate a list of number values arranging for example from 1 to 100000.
I have created a script that does that, but it only prints the output to the screen:
1
2
n
100000
What I need is exactly the same thing but appended to a file with a newline following each value:
1
2
n
100000
This is the script that generates the numbers:
def num_gen(min, max):
for i in range(min, max):
print(i)
print('Enter minimum Appoge value. e.g. 1000')
min_value = int(input())
print("Enter maximum Appoge value. e.g. 3000000")
max_value = int(input())
num_gen(min_value, max_value)
This is the script I wrote in a try to append the output to a file:
def num_gen(min, max):
appoge_list = file('appoge_wordlist.txt', 'w')
for i in range(min, max):
appoge_list.write(str(i))
appoge_list('\n')
appoge_list.close()
print('The appoge_list, appoge_wordlist.txt, has been generated. :)')
print('Enter minimum Appoge value. e.g. 1000')
min_value = int(input())
print("Enter maximum Appoge value. e.g. 3000000")
max_value = int(input())
num_gen(min_value, max_value)
Solution: Okay, I have been trying to achieve the above and then tried to oversimplify everything, I let the code explains it all:
Here is the new script, accepts no args:
def num_gen():
for i in range(10000, 2000001):
print(i)
num_gen()
Then run the command: python appoge_generator.py > appoge_wordlist.txt
To run the script from command line you would python appoge_generator.py I just added the > which means append the output of the procedure to the file appoge_wordlist.txt instead of the screen.
Now I have a 1990001 lines, 14,2 MB wordlist generated in 0.9 seconds. I hope some one finds this useful.
It might be faster/more convenient to use Python to write to the file:
with open('appoge_wordlist.txt', 'w') as file:
for i in range(10000, 2000001):
file.write('{}\n'.format(i))
Another option you might consider:
with open('appoge_wordlist.txt', 'wa') as a_file:
a_file.write('\n'.join([str(val) for val in range(10000, 2000001)]))
Basically open the file that you want to write to using a context manager (the with open(...) syntax) in "write-append" mode (the 'wa' argument), create your string of numbers joined by new lines with '\n'.join(...), and finally write that string to the file with a_file.write(...).
If you want this to be callable from the command line and allow you to pass in any desired start and stop values and any filename, I suggest looking at the excellent argparse module.

Searching a column in a tab delimited array for a specific value

So i'm trying to use a "column_matches" function to search a txt file with data, which i have stored into an array, for a specific value in a column and then print the line containing that value.
The code I have right now looks something like this:
f = open( r'file_directory' )
a = []
for line in f:
a.append(line)
def column_matches(line, substring, which_column):
for line in a:
if column_matches(line, '4', 6):
print (line)
else:
print('low multiplicity')
In this example i'm trying to search the 7th column for the value 4. However, this is currently not printing anything.
I'm a beginner programmer so this might be very wrong, but would love some feedback as I haven't been able to solve it from other peoples questions.
Ideally the program should search all lines and print (or save) every line with a specific value in a specific column!
Edit: example input:
K00889.01 0.9990 8.884922995 10.51 0.114124 89.89 1 153 0.8430 0.8210
K01009.01 0.0000 5.09246539 1.17 0.014236 89.14 1 225 0.7510 0.7270
Your existing function doesn't actually have any logic to handle the case that you are trying to search for. Indeed, you have if column_matches(line, '4', 6): inside the function called column_matches so you imply that it has to call itself in order to determine what action to take... that logically just forms an infinite loop (though in your case, nothing actually runs).
This should be similar to your existing approach but should do what you want. It should be relatively resilient to your actual file structure but let me know if it throws errors.
data = []
with open('example.txt', 'r') as infile:
# Will automatically close the file once you're done reading it
for row in infile:
data.append(row.replace('\n', '').split())
def column_matches(line, target, column_index):
try:
file_data = int(line[column_index])
if file_data == target:
return True
else:
return False
except ValueError:
print('Not a valid number: {}'.format(line[column_index]))
return False
matching_rows = [] # To store items in data that meet our criteria
for line in data:
if column_matches(line, 4, 6):
matching_rows.append(line) # Function has to return True for this to happen

Categories