1
\$\begingroup\$

Is there a way to avoid the first loop in the method shrink? (if and while...)

The utility method shrink should reduce the elements of a double array by picking up elements from the original array "with a regular step respectively offset size"... but the first element should always be included, and the last element too, if possible.

    public static double[] shrink(final double[] data, final int len) {
        if (data.length == 0 || len < 1) {
            throw new IllegalArgumentException("data.length == 0 || len < 1");
        }
        double[] d = new double[len];
        double step = (double) data.length / len;
        if (len > 1) {
            int i = 1;
            while (Math.round(step * (len - 1)) < data.length - 1) {
                step = (double) (data.length + i) / len;
                i++;
            }
        }
        for (int i = 0; i < len; i++) {
            int j = (int) Math.round(i * step);
            d[i] = data[j];
        }
        return d;
    }

    public static void testShrink() {
        double[] data1 = {1, 2, 3, 4, 5, 6};
        for (int i = 1; i <= data1.length; i++) {
            double[] data = new double[i];
            System.arraycopy(data1, 0, data, 0, i);
            for (int j = 1; j <= i; j++) {
                double[] result = shrink(data, j);
                System.out.println(i + " " + j + " " + Arrays.toString(result));
            }
        }
    }

The output of the method testShrink should look like the following:

1 1 [1.0]
2 1 [1.0]
2 2 [1.0, 2.0]
3 1 [1.0]
3 2 [1.0, 3.0]
3 3 [1.0, 2.0, 3.0]
4 1 [1.0]
4 2 [1.0, 4.0]
4 3 [1.0, 2.0, 4.0]
4 4 [1.0, 2.0, 3.0, 4.0]
5 1 [1.0]
5 2 [1.0, 5.0]
5 3 [1.0, 3.0, 5.0]
5 4 [1.0, 2.0, 4.0, 5.0]
5 5 [1.0, 2.0, 3.0, 4.0, 5.0]
6 1 [1.0]
6 2 [1.0, 6.0]
6 3 [1.0, 3.0, 6.0]
6 4 [1.0, 3.0, 4.0, 6.0]
6 5 [1.0, 2.0, 3.0, 5.0, 6.0]
6 6 [1.0, 2.0, 3.0, 4.0, 5.0, 6.0]

I think, it's also a mathematical-like question.

\$\endgroup\$
7
  • \$\begingroup\$ Your interface does not lend itself to a regular step, since you only ask for an output length. A good implementation would vary between two different steps in a dithered manner, or would interpolate. \$\endgroup\$
    – Reinderien
    Oct 5, 2023 at 12:47
  • \$\begingroup\$ What is the purpose and application of this function? Should it interpolate; i.e. should it take the average of two values when it "lands in the middle" between them? \$\endgroup\$
    – Reinderien
    Oct 5, 2023 at 12:50
  • \$\begingroup\$ (your current implementation with round() is basically the dithered one, with a non-uniform step; but could be improved) \$\endgroup\$
    – Reinderien
    Oct 5, 2023 at 13:11
  • \$\begingroup\$ Thanks for your comment @Reinderien. The purpose of the method is to compress a stock market chart horizontally. Therefore, it is unimportant (for me) whether an average would be formed or whether the corresponding elements simply no longer occur. \$\endgroup\$ Oct 5, 2023 at 13:17
  • \$\begingroup\$ @Reinderien the whole class is visible here. \$\endgroup\$ Oct 5, 2023 at 14:02

1 Answer 1

3
\$\begingroup\$

I don't understand the first loop. It seems like a successive approximation calculation for the step size, but that shouldn't be necessary. Instead, we know that you have two defined endpoints of a linear function:

$$f(0) = 0$$ $$f(n-1) = m-1$$ $$i = f(j) = \frac {j(m-1)} {n-1}$$

That gives you your step size. It's easy enough to prevent divide-by-zero by having 1 as the minimum denominator; this also allows for len=0 to act as expected (returning an empty array).

public static double[] shrink(double[] data, int len) {
    if (data.length < 1 || len < 0)
        throw new IllegalArgumentException("data.length < 1 || len < 0");

    double[] d = new double[len];
    double step = (data.length - 1.0d)/Integer.max(len - 1, 1);
    
    for (int j = 0; j < len; ++j) {
        int i = (int)Math.round(j * step);
        d[j] = data[i];
    }
    return d;
}

Note that since this doesn't use interpolation, it introduces alias error.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks, I simply didn't have seen this: double step = (double) (data.length - 1) / (len - 1);. \$\endgroup\$ Oct 6, 2023 at 7:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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