Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spread out array values that are too close

I have a list of values in an array (which is ordered low to high), I am planning to show these values distributed on a line, but as some of the values are close, the points end up overlapping. As the exact values are not important, small adjustments doesn't matter, I'm trying to make some code which spreads any clusters of values so that they are note closer than .5 from any other.

For instance, let's say we have this array:

my_values = { 0.2, 1.3, 2.0, 2.1, 2.5, 3.6, 5.2 }

The 2.0, 2.1 and 2.5 are too close together, so I need to move the so they're not closer than .5 but as close to the actual value as possible. So the optimal solution would be something like:

my_values = { 0.2, 1.1, 1.6, 2.1, 2.6, 3.6, 5.2 }

Here's my code so far, which only makes a lame attempt of a solution (the actual items in the list in my code are objects with get/set functions, but the principle is the same):

...
last_dot = -999 'Low enough
For Each dot In my_values
    If dot.getPos <= last_dot + 0.5 Then
        dot.setPos last_dot + 0.5
    End If
    last_dot = dot.getPos
Next dot

There's thing I'm not sure how to solve: I like to spread them both up and down, so the centre of any cluser is not really moved. So far every move I do just raises the value, and the last value of the cluster gets offset more than the others, prefarably any value moved upwards should have another value move downwards. Keeping the maxinum adjustment of any value as low as possible. So in the lists above when the 2.0 are move down to 1.6 it's then too close to the 1.3, so that has to be moved to 1.1, but in my code I dont know that when checking the 1.3 item. (Not sure if I explained that so anyone can understand =/)

Any help appriciated!

like image 661
Erik Avatar asked Nov 26 '25 21:11

Erik


1 Answers

Iterative relaxation on whole array:

input:

 { 0.2, 1.3, 2.0, 2.1, 2.5, 3.6, 5.2 }

function:

    for (int j = 0; j < 100; j++)// 100 is extreme, maybe 20 is enough for short anomalies
    {
        for (int i = 0; i < t.Length - 1; i++)
        {
            if (t[i] > t[i + 1] - 0.5)
            {
                t[i] -= (t[i] - (t[i + 1] - 0.5)) * 0.1;
            }
        }
        for (int i = t.Length - 1; i >= 1; i--)
        {
            if (t[i] < t[i - 1] + 0.5)
            {
                t[i] -= (t[i] - (t[i - 1] + 0.5)) * 0.1;
            }
        }
    }

Result:

0,2
1,00031552491128
1,61163875308098
2,1160023905259
2,66
3,6
5,2

Warning: O(n) is not efficient when only a few elements need to change.

Edit: corrected the codes as A.S.H. commented.

New output:

0,2
1,21857842635286
1,71823144559425
2,21771136663457
2,71733660405361
3,6
5,2

so it is looks more symmetric now being much closer to the point 2.05 which is mid point of points that are too close.

like image 166
huseyin tugrul buyukisik Avatar answered Nov 29 '25 18:11

huseyin tugrul buyukisik



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!