Search code examples
arraysalgorithmmatharray-algorithms

How to convert variables to an array in a pattern efficiently


Apologies for the clumsy wording, I am struggling on how to describe this problem.

My goal is to write a function that takes in three variables and outputs a 2D array with this pattern:

var foo = function(x, y, z) {
    array = [
        [x + 8, y + 16, z + 35],
        [x + 6, y +  8, z + 30],
        [x + 4, y +  4, z + 20],
        [x + 2, y +  2, z + 10],
        [x    , y     , z     ],
        [x - 2, y +  2, z - 10],
        [x - 4, y +  4, z - 20],
        [x - 6, y +  8, z - 30],
        [x - 8, y + 16, z - 35]
    ]
    return array;
}

Obviously, this way of writing the function seems pretty inefficient.

One way I tried to solve this is with a loop. But my solution introduces three arrays and is also pretty inelegant.

var x_mod = [8,   6,  4,  2, 0, -2,   -4,  -6,  -8];
var y_mod = [16,  8,  4,  2, 0,  2,    4,   8,  16];
var z_mod = [35, 30, 20, 10, 0, -10, -20, -30, -35];

for(let i = 0; i < 9; i++) {
    array[i] = [x + x_mod[i], y + y_mod[i], z + z_mod[i]);
}

Is there a better way of writing this algorithm? I would also appreciate any clues as to what this kind of problem is called, or what I should study to solve it.

Thank you!

EDIT

This is an example of the kind of optimization I was thinking of.

The following function

var bar = function(x, y, z) {
    array = [
        [x + 1, y + 2, z + 3],
        [x + 2, y + 4, z + 6],
        [x + 3, y + 6, z + 9]
    ]
    return array;
}

could also be written in the following way:

var bar = function(x, y, z) {
    array = [];
    for(var i = 1; i < 4; i++)
        array[i] = [x + i, x + i*2, x + i*3];
    return array;
}

This is the kind of "optimization" that I wanted to apply to my original problem. Again, I apologize that I lack the vocabulary to adequately describe this problem.


Solution

  • Is this what you are looking for (in code).

    static class Program
    {
        static void Main(string[] args)
        {
            var m_2 = GenerateMatrix(2, 0.0, 0.0, 0.0);
            // result:
            // |  2.0   2.0   10.0 | + span = 2
            // |  0.0   0.0    0.0 | + 
            // | -2.0  -2.0  -10.0 |
            var m_3 = GenerateMatrix(3, 0.0, 0.0, 0.0);
            // result:
            // |  4.0   4.0   20.0 | +
            // |  2.0   2.0   10.0 | | span = 3
            // |  0.0   0.0    0.0 | +
            // | -2.0  -2.0  -10.0 |
            // | -4.0  -4.0  -20.0 |
            var m_5 = GenerateMatrix(5, 0.0, 0.0, 0.0);
            // result:
            // |  8.0  16.0   40.0 | +
            // |  6.0   8.0   30.0 | |
            // |  4.0   4.0   20.0 | | span = 5
            // |  2.0   2.0   10.0 | | 
            // |  0.0   0.0    0.0 | +
            // | -2.0  -2.0  -10.0 |
            // | -4.0  -4.0  -20.0 |
            // | -6.0  -8.0  -30.0 | 
            // | -8.0 -16.0  -40.0 | 
        }
    
        static double[][] GenerateMatrix(int span, double x, double y, double z)
        {
            var result = new double[2*(span-1)+1][];
            result[span-1] = new double[] { x, y, z };
            for (int i = 0; i < span-1; i++)
            {
                result[span-2-i] = new double[] { x+2*(i+1), y + (2<<i), z + 10*(i+1) };
                result[span+i] = new double[] { x-2*(i+1), y - (2<<i), z - 10*(i+1) };
            }
            return result;
        }
    

    I am using the following rules (use counter=1..span-1). Set the rows symmetrically from the middle since they follow the same pattern with only + or - as a difference:

    1. x values are multiples of twos, x+2*counter and x-2*counter
    2. y values are power of twos, pow(2,counter)=2<<counter
    3. z values are multiples of tens, x+10*counter and x-10*counter