-1

My code is supposed to calculate and print the average pH for every fluid given the file variable name.
This is what I have so far, trying to separate the txt file into parts using split().
I don't really know how to separate the function line by line to calculate each pH and print it separately.

Right now it prints nothing, since it most likely doesn't see a number in the first slot

Function

def average_ph(file_variable):

    result = 0
    line = file_variable.readline()
    found = False
    while line != "" and not found:
        list = line.strip().split(",")
        if list.isnum:
            result += list
    if line != "":
        avg = result / 3
    if not found:
        result = None
        print(avg)
    return avg

Main

file_name = str(input("Enter a file name: "))
file_variable = open(file_name, "r", encoding="utf-8")

File - named: pH.txt

Lemon juice,2.4,2.0,2.2
Baking soda (1 Tbsp) in Water (1 cup),8.4,8.3,8.7
Orange juice,3.5,4.0,3.4
Battery acid,1.0,0.7,0.5
Apples,3.0,3.2,3.5
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
  • As a start, your indentation is not correct. The code should be indented compared to your function signature. – Hakro Nov 28 '16 at 17:27
  • yeah you're right – IncognitoBatman Nov 28 '16 at 17:37
  • 1) You can loop over a file with `for line in file:` 2) Do not name your variable as `list` – OneCricketeer Nov 28 '16 at 17:41
  • 1
    ok, so your list variable contains something like this : ['Lemon Juice', '2.4', '2.0', '2.2'] Now you need to do a for loop on it to get those items. lines = line.strip().split(",") for item in lines if item.isnumeric(): result += item In your while loop, you also need to change the found variable to true sometime, otherwise it will keep on going forever. – Hakro Nov 28 '16 at 17:42

3 Answers3

2

Python3 has a built-in mean function

You just need to figure out how to properly read over a file and split the data.

from statistics import mean

with open("pH.txt") as f:
  for line in f:
    data = line.split(",")
    ph_values = map(float, data[1:])
    print("{}, avg = {:.02f}".format(data[0], mean(ph_values))

As output, should see

Lemon juice, avg = 2.20
Baking soda (1 Tbsp) in Water (1 cup), avg = 8.47
Orange juice, avg = 3.63
Battery acid, avg = 0.73
Apples, avg = 3.23
Community
  • 1
  • 1
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
1

My solution:

def average(numbers):
    return float(sum(numbers)) / max(len(numbers), 1)


def read_average(filename):
    with open(filename) as f:
        dict
        lines = f.readlines()
        for line in lines:
            data = line.split(',')
            name = data[0]
            avg = average([float(i) for i in data[1:]])
            print("{name}: {avg}".format(name=name, avg=avg))

read_average('pH.txt')

Output:

Lemon juice: 2.2
Baking soda (1 Tbsp) in Water (1 cup): 8.466666666666667
Orange juice: 3.6333333333333333
Battery acid: 0.7333333333333334
Apples: 3.233333333333333
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
1

Boy, where to start?

list = line.strip().split(",")
if list.isnum:

First, list is the name of a built-in type in Python, and while you can overshadow that by using it as a variable name, for the sake of not confusing yourself and everybody else, you really shouldn't:

lst = line.strip().split(",")
if lst.isnum:

OK, that's better. lst is an instance of the class that can now still be referred to as list. Now, your if lst.isnum: appears to be an attempt to test the output of a method of that instance. But in Python you can't call methods without typing the parentheses. Without parentheses, currently, your if statement is asking whether the pointer to the method itself is non-zero which, for methods that exist, is always going to be true...

lst = line.strip().split(",")
if lst.isnum():

OK, that's better. Except note that I said, "...for methods that exist". isnum is not a method of the list class so the code will just raise an exception here. You presumably mean the string method .isnumeric:

lst = line.strip().split(",")
if lst.isnumeric():

But of course this is still wrong. You want to test whether items in the list are numeric. Therefore, you need to call some function or method of each item, not of the list itself. Although strings have an isnumeric method, the list class (to which our lst variable belongs) does not. One elegant way around this is to use a "list comprehension":

lst = line.strip().split(",")
lst = [item for item in lst if item.isnumeric()]

But of course that doesn't actually convert the items from strings to numbers. Did you really think you could just add up a bunch of strings and divide by 3?

lst = line.strip().split(",")
lst = [float(item) for item in lst if item.isnumeric()]

OK, now we have a list of actual floating-point numbers that can be manipulated numerically. But we've thrown away the information about which substance we're measuring.

lst = line.strip().split(",")
substance = lst.pop(0)   # remove and store the first item in the list
lst = [float(item) for item in lst if item.isnumeric()]

I would then suggest that you somehow associate each pH value-list/average with its respective substance—otherwise that associative info is going to get lost/corrupted. There are neat ways of doing that with a dict, although currently you have a variable called found that is unused—suggesting that you may be intending to do something like:

if substance == the_particular_substance_we_are_currently_interested_in:
    found = True
    avg = ...

(Note: if you do this, do it inside the loop—you want to check each line to see if it's the target, after all.)

Now, as for your result += lst... Well, you initialized result to 0 so it's an integer, and lst as we know is a list. You can't add a list to an integer—it doesn't make sense. What you presumably want to do is sum the values in the list (and you won't even need result):

    avg = sum(lst) / len(lst)

Note that I'm dividing by whatever the length of lst is, rather than hard-coding the number 3 in there. Hardcoding assumptions like that is a really effective way to set hard-to-find traps for your future self, so let's avoid it.

Good luck.

jez
  • 14,867
  • 5
  • 37
  • 64