Strak
Strak

Reputation: 145

Summing values in an array less than a certain value

I have a 3x3 array with numbers and zeroes. I need to take the absolute difference between the next point, ls[i+1], and the point before it, ls[i]. Here is an example of my list:

ls=[(98.6,99,0),(98.2,98.4,97.1),(97.6,0,98.3)]

The zeroes are faulty data. I need a loop that will:

  1. Take the absolute difference between the future number and the current number in each row,
  2. Make the differences greater than the max difference zero (max diff=1.9 in this case given that the zeroes are faulty data),
  3. Sum together the differences in each row so that I'm left with a list of the sums.

As it stands now, the end result will be:

result=[(0.4,99),(0.2,1.3),(97.6,98.3)]

Given that the zeroes are not good data, differences greater than 1.9 are not an accurate result.

Upvotes: 1

Views: 1174

Answers (3)

Nathaniel Ford
Nathaniel Ford

Reputation: 21249

This should do you. I've broken out your awkward subtraction/clearing of bad values, but you can tail recursively move through the list, building the needed values as you go, filtering out 0s.

def awkward_subtract(a, b):
    if (a is None) or (b is None) or (a == 0) or (b == 0):
        return 0
    else:
        return abs(a - b)

def compare_lists(ls):     
    head, *tail = ls
    if not tail:
        return [list(filter(int(0).__ne__, head))]
    else:
        values = [awkward_subtract(head[x], tail[0][x]) for x in range(0, len(head))]
        return [list(filter(int(0).__ne__, values))] + compare_lists(tail)

You can test it in the REPL*:

>>> ls = [[98.6,99,0],[98.2,98.4,97.1],[97.6,0,98.3]]
>>> compare_lists(ls)
[[0.3999999999999915, 0.5999999999999943], [0.6000000000000085, 1.2000000000000028], [97.6, 98.3]]

(*) I think your test is not quite right, btw.

Note that this uses embedded lists for ease, but it is dead simple to fix that:

ts = [(98.6,99,0),(98.2,98.4,97.1),(97.6,0,98.3)]
ls = [list(t) for t in ts]

Upvotes: 1

zehnpaard
zehnpaard

Reputation: 6243

If you're happy with setting differences over a given maximum difference value to 0, perhaps implement that logic in a 2nd step:

ls=[(98.6,99,0),(98.2,98.4,97.1),(97.6,0,98.3)]

unfiltered = [tuple(abs(x1 - x2) for x1, x2 in zip(tup, tup[1:]))
                for tup in ls]
max_diff = 1.9
results = [tuple((x if x < max_diff else 0) for x in tup)
                for tup in unfiltered]

If you have objects that are not native python lists/tuples but do support indexing, it might be better to do this:

ls=[(98.6,99,0),(98.2,98.4,97.1),(97.6,0,98.3)]

unfiltered = [tuple(abs(item[i] - item[i+1]) for i in range(len(item)-1))
                for item in ls]
max_diff = 1.9
results = [tuple((x if x < max_diff else 0) for x in tup)
                for tup in unfiltered]

Upvotes: 3

OneCricketeer
OneCricketeer

Reputation: 191973

Not sure why the numbers get all messed up when doing the absolute difference, probably something to do with floating point numbers...

ls=[(98.6,99,0),(98.2,98.4,97.1),(97.6,0,98.3)]

def abs_diff(lst, max_diff=1.9):
    n = len(lst)
    if n < 2:
        return lst
    res = []
    for i in range(n-1):
        diff = abs(lst[i] - lst[i+1])
        if diff > max_diff:
            res.append(0)
        else:
            res.append(diff)
    return res

result = map(tuple, map(abs_diff, ls)) 
print result
# [(0.40000000000000568, 0), (0.20000000000000284, 1.3000000000000114), (0, 0)]

Upvotes: 2

Related Questions