2

I have

expected_values =    
[[name, 4, 8, 3]
 [name, 2, 6, 9]
 [name, 3, 6, 2]]

and I want to do something similar to dividing the 2nd value by the 1st value, then multiply that by 3, then append the value to the end of the list. So the final product would look like

expected_values = 
[[name, 4, 8, 3, 6]
 [name, 2, 6, 9, 9]
 [name, 3, 6, 2, 6]]

What I have so far is

for name in range(0,len(expected_values)):
    total = 0
    pa = expected_values[name][1]
    pa = int(pa)
    for s in range(0,len(expected_values)):
        singles = expected_values[s][2]
        singles = int(singles)
        total = total + ((singles/pa)*3)
    expected_values.append(total)

I have int(pa) in there because it's being imported from a CSV file and apparently it imports everything as strings, so I have to convert it to do any math on it.

I'm very new to Python -- doing this as a summer project to learn the language -- and I'm kind of shaky on the indexing of lists within lists, especially inside these loops.

jbf
  • 171
  • 2
  • 11
  • This is not a duplicate question or anything, but read through this: https://stackoverflow.com/questions/19184335/is-there-a-need-for-rangelena – Two-Bit Alchemist Jul 24 '15 at 20:29
  • That's how I had it written originally, after looking at examples of other people's codes, but it is more intuitive to me to write it this way. Saying something like "for name in expected_values:" is a little confusing to me. I'm going to try to rewrite it after I get it actually working. Thanks for the link though, I'll save it. – jbf Jul 24 '15 at 20:36
  • check out this line `expected_values.append(total)`. You're appending to the outer list, but really you want to append to whichever inner list you're working on `expected_values[name].append(total)` – ate50eggs Jul 24 '15 at 20:37
  • When you say, "multiply that 3", do you mean multiply the result by 3 or by the 3rd element? – skrrgwasme Jul 24 '15 at 20:41
  • I meant multiply the result by 3, as in the example. Sorry for the typo. – jbf Jul 24 '15 at 20:46

2 Answers2

1

Just iterate over the list appending the sub[2]/sub[1] * 3,lists are mutable and append is an inplace operation so you are modifying the original object/list each time you append, you don't need an index the sublists or to create new lists:

expected_values =    [["name", 4, 8, 3], ["name", 2, 6, 9], ["name", 3, 6, 2]]

for sub in expected_values:
    sub.append(int(sub[2]) / int(sub[1]) * 3)

print(expected_values)

Output:

[['name', 4, 8, 3, 6], ['name', 2, 6, 9, 9], ['name', 3, 6, 2, 6]]

You just want to make sure the sub[2] element is not 0 to avoid a ZeroDivisionError and use a default value or whatever is preferable:

for sub in expected_values:
    a,b = int(sub[1]), int(sub[2])
    sub.append(b / a * 3 if b else 0)

print(expected_values)

sub[2] extracts the third element i.e 8 in your first sublist, sub[1] gets the second i.e 4 and you just need to multiply and append.

If you have actual string digits just call int(sub[2]) etc.. Depending on what you want to happen you may also want to cast at least one to float if you are using python2, / will floor using ints with python 2.

Padraic Cunningham
  • 176,452
  • 29
  • 245
  • 321
  • Thanks, I copied your first block of code almost exactly and it works. I'm not super clear on the logic of it but I'm going to study it and try to see. – jbf Jul 24 '15 at 20:45
  • @jbf, you can simply iterate over a list in python, it is not like c where you use sizeof, indexing etc.. lists are mutable in python which is actually very important to remember or you can end up with some subtle bugs so when you change the list by appending to the end of it you are changing the original object, you are holding references to the each sublist in your `expected_values` list. – Padraic Cunningham Jul 24 '15 at 20:50
0

In addition to the other answer here, it is also possible to do this in one line:

name = "something"

expected_values =  [
                [name, 4, 8, 3],
                [name, 2, 6, 9],
                [name, 3, 6, 2]]

expected_values = [l + [(int(l[2])/int(l[1]))*3] for l in expected_values]

print(expected_values)

Produces:

[['something', 4, 8, 3, 6], ['something', 2, 6, 9, 9], ['something', 3, 6, 2, 6]]

This comprehension iterates over the outer list. For each sublist within it, a new list of one item that is the result of the mathematical operation is added to it.

As people have pointed out in the comments, this will have slightly lower performance (because it creates new lists) and can be harder to read, so the other answer is probably a better choice. However, since you (the OP) are new to the language, I thought it could be useful for you to see a list comprehension being used as an alternative.

skrrgwasme
  • 9,358
  • 11
  • 54
  • 84
  • this creates a new list, it does not modify the list – Padraic Cunningham Jul 24 '15 at 20:34
  • @PadraicCunningham Yes, but end result is the same. The OP didn't specify that a new list couldn't be created. – skrrgwasme Jul 24 '15 at 20:37
  • Creating new lists and sublists is not the same as an `0(1)` append, they also actually use append *then append the value to the end of the list* – Padraic Cunningham Jul 24 '15 at 20:38
  • 1
    Not to mention that's one ugly list comprehension. If I saw that in code I was maintaining, I would likely put it on my to-do list to rewrite it ASAP. – Two-Bit Alchemist Jul 24 '15 at 20:43
  • @PadraicCunningham I agree. But the OP also didn't specify any speed requirements. I'm just suggesting an alternative approach, and since he/she is obviously new to the language, I thought this would be a good opportunity to introduce comprehensions. I agree with Two-Bit Alchemist that your answer is cleaner though. – skrrgwasme Jul 24 '15 at 20:44