3
\$\begingroup\$

I have a simple task I want to do, I want to compare two arrays like this:

array 1 of data:  [0.0, 92.6, 87.8, 668.8, 0.0, 86.3, 0.0, 147.1]
array 2 of data:  [16.7, 0.0, 0.0, 135.3, 0.0, 205.5, 0.0, 93.8]

I want to find the difference between each value by index, and if the difference is lower than 50%, keep the value of the second array in a third array.

array 3 of data : [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 93.8]

Now I believe using a for loop would be the best option, iterating through each array since both have the same length, the code below is part of my code, array1 and array2 are arrays like above.

for scan in sensor:
        #here is some code where we build the Array1 and Array 2 from serial data which is inside the loop.
    if specialcount ==1: #build the first array
      #get data from dict and build first array
      datadict={ 0:[], 1:[], 2:[], 3:[], 4:[], 5:[], 6:[], 7:[], }
    if specialcount ==2: #build the second array.
        #get data from dict and build second array
      datadict={ 0:[], 1:[], 2:[], 3:[], 4:[], 5:[], 6:[], 7:[], }
    if specialcount ==3: #after we build 2 arrays, specialcount goes to 3, and we now compare the arrays
            indexsizeofArray1 = len(array1)
            indexsizeofArray2 = len(array2)
            if indexsizeofArray1 != indexsizeofArray2:
                print ("array mismatch, try again")
                break
            elif indexsizeofArray1 == indexsizeofArray2:
                print("array match, proccessing")
                array3 = [0,0,0,0,0,0,0,0]
                for X in range (indexsizeofArray2):
                    difference = array2[X]-array1[X]
                    fiftypercent = array1[X]-(array1[X]/2)
                    lowerrange = int(array1[X]-fiftypercent)
                    upperrange = int(array1[X]+fiftypercent)
                    if array2[X] in range (lowerrange,upperrange):
                        array3[X]=array2[X]
                    if X == indexsizeofArray2:
                        print("final array: ",array3)
    specialcount +=1

Above is my code ,I do get the result I want of course, but I believe I could make it cleaner mostly because I am in the code transforming float to int as they work with the range function. I am sure there is a cleaner way of doing this , that specialcount==3 is my condition since I build the 2 arrays inside the forloop before as soon as the second array is built, then we, this is inside a loop where I am polling constantly a sensor, the sensor is special in the sense that if I stop polling it and go out of the loop, it will not work again unless I restart it , as such I must be inside this loop all the time.

I am sure I can improve the speed of it if slightly, mostly on the reinitialization of the datadict, since I initialized it before , however inside the loop I populate it with the data up until a certain point, in which I then create the first array of data, and clear it so I can rebuild it. The goal is to build two arrays of 2 different variables that must be related, once those 2 lists are built, I need to compare them, ensure that they are not that different and if they are not , pass it to another function , if its too different, the value for that index in the list is 0 .

\$\endgroup\$
4
  • 5
    \$\begingroup\$ \$ 50 \% \$ of what? there are 2 values. \$\endgroup\$ – hjpotter92 Oct 12 '20 at 19:25
  • \$\begingroup\$ Can you provide a complete example, including input and output? Also, you're dealing with plain Python lists, right? \$\endgroup\$ – AMC Oct 13 '20 at 0:10
  • \$\begingroup\$ specialcount is incremented every time through the loop. The if blocks only execute for values 1 to 3. After that, it's an infinite loop that doesn't do anything. \$\endgroup\$ – RootTwo Oct 13 '20 at 1:55
  • \$\begingroup\$ 50% of what, and how is this an appropriate threshold? "-50%" is 2:1, "+50%" 2:3. code where we build the Array1 I don't see that. I see datadict set to a weird literal dict from 0…7 to empty lists - never to be used. \$\endgroup\$ – greybeard Oct 13 '20 at 7:31
5
\$\begingroup\$

Don't use the loop-switch antipattern

If you have three different things that have to be done in order, just write them in that order. Don't put a loop around them with if-statements inside to check what has to be done that iteration; loops are for doing the same task over and over. What you are doing has a name: it is the loop-switch antipattern. Instead, just write:

#get data from dict and build first array
datadict={ 0:[], 1:[], 2:[], 3:[], 4:[], 5:[], 6:[], 7:[], }

#get data from dict and build second array
datadict={ 0:[], 1:[], 2:[], 3:[], 4:[], 5:[], 6:[], 7:[], }

#we now compare the arrays
...

I assume that's not the real code. If each of the three tasks is of course much longer than what you wrote, then it helps to put them in functions.

Split the problem up into smaller sections

It always helps to break up a problem into smaller sections, and for example you can then handle each sub-problem in a separate function. In this case, looping over the arrays can be split from deciding whether or not to keep a value. So:

keep_within_fifty_percent(a, b):
    fiftypercent = a // 2
    lower = a - fiftypercent
    upper = a + fiftypercent

    if b in range(lower, upper):
        return b;
    else:
        return 0

...

#we now compare the arrays
if len(array1) != len(array2):
    # handle error here
    ...

array3 = [keep_within_fifty_percent(a, b) for a, b in zip(array1, array2)]
print("final array: ", array3)
\$\endgroup\$
6
  • \$\begingroup\$ Thanks for the comments, i have the if statement inside for a simple reason, since i am getting data constantly from the first loop where I poll a sensor, I fill there a dictionary, which then I use the "if specialcount " condition to fill two different arrays with different data. I think if I remove the loop switch, I ran into the issue of basically building two identical arrays with the same data instead of two arrays with different data!. Would splitting part of the code to its own function introduce any delay? I am polling data from a serial port sensor, any delay introduces data loss \$\endgroup\$ – Victor J Mytre Oct 12 '20 at 21:20
  • 2
    \$\begingroup\$ If performance is a critical issue, Python is the wrong language to use. Consider using C or C++ in that case. That said, I don't think there is a significant overhead for putting code in their own functions, but if you really want to know, you should benchmark your code. \$\endgroup\$ – G. Sliepen Oct 12 '20 at 21:24
  • 1
    \$\begingroup\$ lower is same as \$ a / 2 \$, you don't need integral value. \$\endgroup\$ – hjpotter92 Oct 12 '20 at 23:49
  • 2
    \$\begingroup\$ also, lower <= b < upper vs range? \$\endgroup\$ – hjpotter92 Oct 12 '20 at 23:50
  • 1
    \$\begingroup\$ @hjpotter92 You're right, the calculation can be simplified even more, like in Acccumulation's answer. \$\endgroup\$ – G. Sliepen Oct 13 '20 at 6:07
5
\$\begingroup\$

You can just use comprehensions:

def get_third_value(value1, value2):
    if abs(value1 - value2) < value1/2:
        return value2
    return 0

if len(array1) != len(array2):
    print ("array mismatch, try again")
    break
print("array match, proccessing")
array3 = [get_third_value(array1[i], array2[i]) 
    for i in range(len(array1))]
print("final array: ",array3)

If you convert your data to Pandas Series, you can just do

(abs(array1-array2)<array1/2)*array2

Some notes on your code:

array1[X]-(array1[X]/2) baffles me. Why not just write array1[X]/2?

You don't need to create special variables to store the lengths of the data, you can just compare them directly.

range is for creating an iterable. If you want to find out whether a number is between two values, you should use inequalities.

I would expect that X == indexsizeofArray2 would always return False; range creates an iterable up to the argument. range(n) does not include n.

This also means that range(a-b,a+b) starts at a-b but ends at a+b-1.

\$\endgroup\$
1
  • \$\begingroup\$ Instead of using for i in range(len(array1)) you can just do [get_third_value(x, y) for x,y in zip(array1, array2)] \$\endgroup\$ – Tomerikoo Oct 13 '20 at 8:04

Not the answer you're looking for? Browse other questions tagged or ask your own question.