Ad

Advanced List Comprehension: Creating Averages

- 1 answer

I have a list, each element in the list in a list containing 2 numbers separated by a comma.

I have to treat the first items in each list in relation with each other, same with the second ones.

Given a list, I have to replace the first number of each nested list with the average of the number, the first number in the list to its right and the first number in the list to its left. same to the second number. For the first nested list, I have to replace it the average or the number itself and its matching number in the list to its right. For the last, the same with the list to its left.

For example:

[[1, 1], [7, 7], [20, 20], [9, 9], [-12, -12]]

would be:

[[(1+7)/2, (1+7)/2], [(7+1+20)/3, (7+1+20)/3], [(20+7+9)/3, (20+7+9)/3], [(9+20-12)/3, (9+20-12)/3], [(-12+9)/2, (-12+9)/2]]

and thus:

[[4, 4], [9, 9], [12, 12], [5, 5], [-2, -2]]

because we are returning ints.

I have a code but it only prints the average, which is kind of clunky. Please help me to point me to the right direction on how to calculate the elements, and create the new list.

Also, I would like to use only loops and basic list comprehensions, so I can understand the logic.

This is my code so far:

def lpf(lst):
for i in range(len(lst)):
    for j in range(2):
        if i == 0:
            lst[i][j] = int((lst[i][j] + lst[i+1][j]) / 2)
        elif 0 < i < (len(lst) - 1):
            lst[i][j] = int((lst[i-1][j] + lst[i][j] + lst[i+1][j]) / 3)
        elif i == len(lst) - 1:
            lst[i][j] = int((lst[i-1][j] + lst[i][j]) / 2)
return lst

And we have to assume the items in the list won't always be the same.

I seem to understand my code's problem - Once I change the first element, the next iteration happens over the new element and not the original. Yet I cant think about how to solve this.

Ad

Answer

You wanted list-comprehension, I give you list-comprehension:

[[sum(s[p] for s in l[i-1 if i > 0 else 0:i+2])//(2 if i in (0,len(l)-1) else 3) for p in range(2)] for i in range(len(l))]

In all serious though, I would recommend breaking this down into a for-loop which contains the inner list-comprehension as it is just so unreadable.


Example of it working:

>>> l = [[1, 1], [7, 7], [20, 20], [9, 9], [-12, -12]]
>>> [[sum(s[p] for s in l[i-1 if i > 0 else 0:i+2])//(2 if i in (0,len(l)-1) else 3) for p in range(2)] for i in range(len(l))]
[[4, 4], [9, 9], [12, 12], [5, 5], [-2, -2]]

Exploded form without list-comprehensions:

output = []
for i in range(len(l)):
    if i == 0:
        group = l[i:i+2]
        averaged = [(group[0][0] + group[1][0])//2,
                    (group[0][1] + group[1][1])//2]
        output.append(averaged)
    elif i == len(l)-1:
        group = l[i-1:i+1]
        averaged = [(group[0][0] + group[1][0])//2,
                    (group[0][1] + group[1][1])//2]
        output.append(averaged)
    else:
        group = l[i-1:i+2]
        averaged = [(group[0][0] + group[1][0] + group[2][0])//3,
                    (group[0][1] + group[1][1] + group[2][0])//3]
        output.append(averaged)

which gives output as before:

[[4, 4], [9, 9], [12, 12], [5, 5], [-2, -2]]
Ad
source: stackoverflow.com
Ad