Total from text file - python

I have a text file with the data with numbers of good and bad of a product by each gender
Male 100 120
Female 110 150
How can I calculate the total from this text file for both gender so that it prints out 480
Here is my attempt to code:
def total():
myFile = open("product.txt", "r")
for result in myFile:
r = result.split()
print(r[1]+r[2])
total()
It prints outs what the column has but it doesn't add them

The result of split is a sequence of strings, not of integers.
"Adding" two strings with + concatenates the strings.
Example interaction with enough clues for you to solve it:
>>> s = "123 456"
>>> ss = s.split()
>>> ss
['123', '456']
>>> ss[0] + ss[1]
'123456'
>>> int(ss[0])
123
>>> int(ss[1])
456
>>> int(ss[0]) + int(ss[1])
579
When you get unexpected results, opening your interpreter and looking at things interactively usually provides plenty of clues.

You need to convert each of the split text entries into an integer, and keep a running total as follows:
def total():
the_total = 0
with open("product.txt", "r") as myFile:
for result in myFile:
r = result.split()
the_total += int(r[1]) + int(r[2])
return the_total
print(total())
This would display:
480
Using with will automatically close the file for you.

Yet another one
def total():
with open('product.txt') as f:
nums = (int(el) for r in f for el in r.split()[1:])
return sum(nums)
print(total())
It works for any number of columns you may have in each row
e.g. with four columns
Male 111 222 333 444
Female 666 777 888 999
produces
4440

As mentioned in the comments by jonrsharpe, you aren't adding the previous values.
Since you want to add everything, keep track of the previous values and add the new lines (all converted to integer). Change your code to:
def total():
t = 0
with open("product.txt", "r") as myFile:
for result in myFile:
r = result.split()
t += int(r[1]) + int(r[2])
return t
print(total()) # 480
Since this got chosen, I'm editing to include file closing.
Mentioned by Martin Evans:
Using with will automatically close the file for you.

>>> def total():
myfile = open("/home/prashant/Desktop/product.txt" , "r")
for res in myfile:
r = res.split()
print (int(r[0])+int(r[1]))
str isn't converted into int that's your problem

Related

How do I include the last instance of the condition met for the if statement?

I have a document that I am reading and writing to. Information is listed with a timestamp at the beginning of every entry. I am trying to populate the dateNTimeArr array with datetime objects for every entry but I notice that the last entry is not appending to the array, no matter how many entries I have. I'm not sure how to solve this.
this an example of the text file I am reading and writing to.
In this example, the array will populate with the datetime objects I create from the first and second entry but it doesn't append the last one.
2021-08-10 16:26:12
123
123
123
123
123
2021-08-10 16:26:28
123
123
123
123
123
2021-08-10 16:27:15
123
123
123
123
123
I tried removing the '\n' from the start of the while loop which seemed to work but the next time I ran the code, it messed with the format and kind of broke. Sorry in advance for the lack of structure to my code.
f = open("filename", "r")
dateNTimeArr = []
for line in f:
if "2021" in line:
datentime = line.split(" ")
datePart = datentime[0]
timePart = datentime[1]
hours, mins, secs = timePart.split(":")
year, month, day = datePart.split("-")
date1 = date(int(year), int(month), int(day))
time1 = time(int(hours), int(mins), int(secs))
datetime1 = datetime.combine(date1, time1)
dateNTimeArr.append(datetime1)
f.close()
f = open("filename", "a+")
submitBool = FALSE
while submitBool == FALSE:
f.write('\n')
f.write(now)
f.write('\n')
f.write(aQuantity.get())
f.write('\n')
f.write(bQuantity.get())
f.write('\n')
f.write(cQuantity.get())
f.write('\n')
f.write(dQuantity.get())
f.write('\n')
f.write(eQuantity.get())
submitBool = TRUE
f.close()
As Bramar mention, the list has 3 elements, you never printed it to check that.
Also, you have a few mistakes, in the while loop. The bool values are True and False not TRUE or FALSE.
And the loop will only run once because you changed it to True at the end of it.

How to get read strings from a list(a txt file) and print them out as ints, strings, and floats?

I've tried literally everything to make this work. What i'm trying to do is take a file, assign each line a variable, and then set the type of the variable. It's reading it in the list as [ and ' being a line number, and I don't know what to do. I also have lists inside of the file that I need to save.
My error is:
ValueError: invalid literal for int() for base 10: '['
My code is:
def load_data():
f = open(name+".txt",'r')
enter = str(f.readlines()).rstrip('\n)
print(enter)
y = enter[0]
hp = enter[1]
coins = enter[2]
status = enter[3]
y2 = enter[4]
y3 = enter[5]
energy = enter[6]
stamina = enter[7]
item1 = enter[8]
item2 = enter[9]
item3 = enter[10]
equipped = enter[11]
firstime = enter[12]
armorpoint1 = enter[13]
armorpoint2 = enter[14]
armorpoints = enter[15]
upgradepoint1 = enter[16]
upgradepoint2 = enter[17]
firstime3 = enter[18]
firstime4 = enter[19]
part2 = enter[20]
receptionist = enter[21]
unlocklist = enter[22]
armorlist = enter[23]
heal1 = enter[24]
heal2 = enter[25]
heal3 = enter[26]
unlocked = enter[27]
unlocked2 = enter[28]
float(int(y))
int(hp)
int(coins)
str(status)
float(int(y2))
float(int(y3))
int(energy)
int(stamina)
str(item1)
str(item2)
str(item3)
str(equipped)
int(firstime)
int(armorpoint1)
int(armorpoint2)
int(armorpoints)
int(upgradepoint1)
int(upgradepoint2)
int(firstime3)
int(firstime4)
list(unlocklist)
list(armorlist)
int(heal1)
int(heal2)
int(heal3)
f.close()
SAMPLE FILE:
35.0
110
140
Sharpshooter
31.5
33
11
13
Slimer Gun
empty
empty
Protective Clothes
0
3
15
0
3
15
0
1
False
False
['Slime Slicer', 'Slimer Gun']
['Casual Clothes', 'Protective clothes']
4
3
-1
{'Protective Clothes': True}
{'Slimer Gun': True}
The .readlines() function returns a list, each item containing a separate line. In order to strip the newline from each of the lines, you can use a list comprehension:
f = open("data.txt", "r")
lines = [line.strip() for line in f.readlines()]
You can then proceed to cast each item in the list separately, as you have, or try to somehow automatically infer the type in a loop. This would be easier if you formatted the example file more like a configuration file. This thread has some relevant answers:
Best way to retrieve variable values from a text file?
I think its better if you read the file this way, which first reads and removes whitespace and then splits into lines. Then you can set a variable to each line (also you need to set the result of changing variable types to the variable).
For lists, you may need a function to extract the list from the string. However if you aren't expecting security breaches then using eval() should be fine.
def load_data():
f = open(name+".txt",'r')
content = f.read().rstrip()
lines = content.split("\n")
y = float(int(enter[0]))
hp = int(enter[1])
coins = int(enter[2])
status = enter[3]
# (etc)
unlocklist = eval(enter[22])
armorlist = eval(enter[23])
f.close()

Double if conditional in the line.startswith strategy

I have a data.dat file with this format:
REAL PART
FREQ 1.6 5.4 2.1 13.15 13.15 17.71
FREQ 51.64 51.64 82.11 133.15 133.15 167.71
.
.
.
IMAGINARY PART
FREQ 51.64 51.64 82.12 132.15 129.15 161.71
FREQ 5.64 51.64 83.09 131.15 120.15 160.7
.
.
.
REAL PART
FREQ 1.6 5.4 2.1 13.15 15.15 17.71
FREQ 51.64 57.64 82.11 183.15 133.15 167.71
.
.
.
IMAGINARY PART
FREQ 53.64 53.64 81.12 132.15 129.15 161.71
FREQ 5.64 55.64 83.09 131.15 120.15 160.7
All over the document REAL and IMAGINARY blocks are reported
Within the REAL PART block,
I would like to split each line that starts with FREQ.
I have managed to:
1) split lines and extract the value of FREQ and
2) append this result to a list of lists, and
3) create a final list, All_frequencies:
FREQ = []
fname ='data.dat'
f = open(fname, 'r')
for line in f:
if line.startswith(' FREQ'):
FREQS = line.split()
FREQ.append(FREQS)
print 'Final FREQ = ', FREQ
All_frequencies = list(itertools.chain.from_iterable(FREQ))
print 'All_frequencies = ', All_frequencies
The problem with this code is that it also extracts the IMAGINARY PART values of FREQ. Only the REAL PART values of FREQ would have to be extracted.
I have tried to make something like:
if line.startswith('REAL PART'):
if line.startswith('IMAGINARY PART'):
code...
or:
if line.startswith(' REAL') and line.startswith(' FREQ'):
code...
But this does not work. I would appreciate if you could help me
It appears based on the sample data in the question that lines starting with 'REAL' or 'IMAGINARY' don't have any data on them, they just mark the beginning of a block. If that's the case (and you don't go changing the question again), you just need to keep track of which block you're in. You can also use yield instead of building up an ever-larger list of frequencies, as long as this code is in a function.
def read_real_parts(fname):
f = open(fname, 'r')
real_part = False
for line in f:
if line.startswith(' REAL'):
real_part = True
elif line.startswith(' IMAGINARY'):
real_part = False
elif line.startswith(' FREQ') and real_part:
FREQS = line.split()
yield FREQS
FREQ = read_real_parts('data.dat') #this gives you a generator
All_frequencies = list(itertools.chain.from_iterable(FREQ)) #then convert to list
Think of this as a state machine having two states. In one state, when the program has read a line with REAL at the beginning it goes into the REAL state and aggregates values. When it reads a line with IMAGINARY it goes into the alternate state and ignores values.
REAL, IMAGINARY = 1,2
FREQ = []
fname = 'data.dat'
f = open(fname)
state = None
for line in f:
line = line.strip()
if not line: continue
if line.startswith('REAL'):
state = REAL
continue
elif line.startswith('IMAGINARY'):
state = IMAGINARY
continue
else:
pass
if state == IMAGINARY:
continue
freqs = line.split()[1:]
FREQ.extend(freqs)
I assume that you want only the numeric values; hence the [:1] at the end of the assignment to freqs near the end of the script.
Using your data file, without the ellipsis lines, produces the following result in FREQ:
['1.6', '5.4', '2.1', '13.15', '13.15', '17.71', '51.64', '51.64', '82.11', '133.15', '133.15', '167.71', '1.6', '5.4', '2.1', '13.15', '15.15', '17.71', '51.64', '57.64', '82.11', '183.15', '133.15', '167.71']
You would need to keep track of which part you are looking at, so you can use a flag to do this:
section = None #will change to either "real" or "imag"
for line in f:
if line.startswith("IMAGINARY PART"):
section = "imag"
elif line.startswith('REAL PART'):
section = "real"
else:
freqs = line.split()
if section == "real":
FREQ.append(freqs)
#elif section == "imag":
# IMAG_FREQ.append(freqs)
by the way, instead of appending to FREQ then needing to use itertools.chain.from_iterable you might consider just extending FREQ instead.
we start with a flag set to False. if we find a line that contains "REAL", we set it to True to start copying the data below the REAL part, until we find a line that contains IMAGINARY, which sets the flag to False and goes to the next line until another "REAL" is found (and hence the flag turns back to True)
using the flag concept in a simple way:
with open('this.txt', 'r') as content:
my_lines = content.readlines()
f=open('another.txt', 'w')
my_real_flag = False
for line in my_lines:
if "REAL" in line:
my_real_flag = True
elif "IMAGINARY" in line:
my_real_flag = False
if my_real_flag:
#do code here because we found real frequencies
f.write(line)
else:
continue #because my_real_flag isn't true, so we must have found a
f.close()
this.txt looks like this:
REAL
1
2
3
IMAGINARY
4
5
6
REAL
1
2
3
IMAGINARY
4
5
6
another.txt ends up looking like this:
REAL
1
2
3
REAL
1
2
3
Original answer that only works when there is one REAL section
If the file is "small" enough to be read as an entire string and there is only one instance of "IMAGINARY PART", you can do this:
file_str = file_str.split("IMAGINARY PART")[0]
which would get you everything above the "IMAGINARY PART" line.
You can then apply the rest of your code to this file_str string that contains only the real part
to elaborate more, file_str is a str which is obtained by the following:
with open('data.dat', 'r') as my_data:
file_str = my_data.read()
the "with" block is referenced all over stack exchange, so there may be a better explanation for it than mine. I intuitively think about it as "open a file named 'data.dat' with the ability to only read it and name it as the variable my_data. once its opened, read the entirety of the file into a str, file_str, using my_data.read(), then close 'data.dat' "
now you have a str, and you can apply all the applicable str functions to it.
if "IMAGINARY PART" happens frequently throughout the file or the file is too big, Tadgh's suggestion of a flag a break works well.
for line in f:
if "IMAGINARY PART" not in line:
#do stuff
else:
f.close()
break

Python 2.7: how to append lines which contain both string & numeric values to text file?

I want to append following line to my text file:
Degree of polarization is 8.23 % and EVPA is 45.03 degree.
i.e. I want both string and numeric values to be appended.
I want to append above line with different numeric values after each run of my python code.
Any help will be appreciated.
For example
>>> a = 10.5
>>> with open("myfile.txt","a") as f:
... f.write(a)
gives me error.
Do you mean something like this:
while True:
polarization = getPolarization()
evpa = getEvpa()
my_text = "Degree of polarization is {} % and EVPA is {} degree.".format(polarization, evpa)
with open("test.txt", "a") as myfile:
myfile.write(my_text)
Maybe you should also write what have you tried yet and what problems/errors occurred
You can only write strings to files.
Strings can be concatenated:
>>> 'a' + 'b'
'ab'
Numbers can be converted to strings:
>>> str(4)
'4'
>>> str(5.6)
'5.6'
You should be able to get started with that.
Also, Python's string formatting will automatically do this for you:
>>> '{} % and {} degree'.format(6.7, 8.9)
'6.7 % and 8.9 degree'
Or with a more readable format using keywords:
>>> '{polarization} % and {evpa} degree'.format(polarization=6.7, evpa=8.9)
'6.7 % and 8.9 degree'

Removing first character from string

I am working on a CodeEval challenge and have a solution to a problem which takes a list of numbers as an input and then outputs the sum of the digits of each line. Here is my code to make certain you understand what I mean:
import sys
test_cases = open(sys.argv[1], 'r')
for test in test_cases:
if test:
num = int(test)
total =0
while num != 0:
total += num % 10
num /= 10
print total
test_cases.close()
I am attempting to rewrite this where it takes the number as a string, slices each 0-index, and then adds those together (curious to see what the time and memory differences are - totally new to coding and trying to find multiple ways to do things as well)
However, I am stuck on getting this to execute and have the following:
import sys
test_cases = open(sys.argv[1], 'r')
for test in test_cases:
sums = 0
while test:
sums = sums + int(str(test)[0])
test = test[1:]
print sums
test_cases.close()
I am receiving a "ValueError: invalid literal for int() with base 10: ''"
The sample input is a text file which looks like this:
3011
6890
8778
1844
42
8849
3847
8985
5048
7350
8121
5421
7026
4246
4439
6993
4761
3658
6049
1177
Thanks for any help you can offer!
Your issue is the newlines (eg. /n or /r/n) at the end of each line.
Change this line:
for test in test_cases:
into this to split out the newlines:
for test in test_cases.read().splitlines():
try this code:
tot = 0
with open(sys.argv[1], 'r') as f:
for line in f:
try:
tot += int(line)
except ValueError:
print "Not a number"
print tot
using the context manager (with...) the file is automatically closed.
casting to int filter any empty or not valid value
you can substitute print with any other statement optimal for you (raise or pass depending on your goals)

Categories