1

I want find a record in a list of lists, on this case is the 3 and get the substract of their element [2] with the element [2] from their previous record

mylist = [
["acc", 2, 3.1,4.3,"pe"],
["fir", 1, 3.5,5.2,"p1"],
["sec", 3, 1.1,5.8,"pe"],
["set", 5, 6.2,6,2,"pa"],
["eve", 8, 5.4,5.7,"io"], 
["ewa", 3, 4.1,4.1,"po"]
]

The result should be:

3.5 - 1.1 and 5.2 - 5.8
5.4 - 4.1 and 5.7 - 4.1


I can get it with this code, but I want learn some better and simpler way to do it, thanks.

i=0    
while i<len(mylist)-1:
        if mylist[i][1] == 3:
            print mylist[i-1][2]-mylist[i][2]
            print mylist[i-1][3]-mylist[i][3]
        i+=1
Goku
  • 1,750
  • 5
  • 23
  • 35

3 Answers3

1

Instead of using a while loop, you can use the for loop.

for row1, row2 in zip(mylist[1:], mylist[0:-1]):
    if row1[1] == 3:
        print [y - x for x, y in zip(row1[2:4], row2[2:4])]

You could also save some memory by utilizing the izip method instead of the zip method.

from itertools import izip

for row1, row2 in izip(mylist[1:], mylist[0:-1]):
    if row1[1] == 3:
        print [y - x for x, y in izip(row1[2:4], row2[2:4])]

These code snippets will output

[2.4, -0.6]
[1.3, 1.6]

izip() uses generators instead of lists. This may boost the performance of your script, and will save you memory.

If you prefer a shorter version of the above code, you can use list comprehensions.

from itertools import izip
print [[y - x for x, y in izip(row1[2:4], row2[2:4])] for row1, row2 in izip(mylist[1:], mylist[:-1]) if row1[1] == 3]

Output:

[[2.4, -0.6], [1.3, 1.6]]

You could also make a generator of the above

for val in ([y - x for x, y in zip(row1[2:4], row2[2:4])] for row1, row2 in zip(mylist[1:], mylist[:-1]) if row1[1] == 3):
    print val

Output:

[2.4, -0.6]
[1.3, 1.6]

Remember that by doing this, the generator is exhausted after you have accessed the last item, so you shouldn't use a generator for this if you need to store the values which is outputted.

Community
  • 1
  • 1
Steinar Lima
  • 7,644
  • 2
  • 39
  • 40
0

You could save the qualifying indices off using a generator and use the generator in a subsequent step, like so

gen = (x for x, y in enumerate(mylist) if y[1] == 3)
[(mylist[x-1][2] - mylist[x][2], mylist[x-1][3] - mylist[x][3]) for x in gen]
[(2.4, -0.5999999999999996), (1.3000000000000007, 1.6000000000000005)]
iruvar
  • 22,736
  • 7
  • 53
  • 82
0

Short answer

for previous, current in zip(mylist[:-1], mylist[1:]):
    if current[1] == 3:
        print previous[2] - current[2]
        print previous[3] - current[3]

Long answer

What I'm doing is zipping the list without the first element and the list without the last one:

>>> z = [10, 20, 30, 40, 50]
>>> z[:-1]
[10, 20, 30, 40]
>>> z[1:]
[20, 30, 40, 50]
>>> zip(z[:-1], z[1:])
[(10, 20), (20, 30), (30, 40), (40, 50)]

By iterating over the zipped list, we have access in turn to both the previous and the current item, which is clear by the names I gave the variables in the for loop.

Note that my solution handles properly the case where there are zero or one items in your list. When this happens, the zipped list is empty, so the for loop does nothing.

Roberto Bonvallet
  • 31,943
  • 5
  • 40
  • 57