How to initialize a big non-calculatable 2d array

Hi guys,
is there a better way to initialize a 2D array with very specific values in Kotlin?

in Java I had:

public static final int[][] coordinates =
    {
        {0,0,0}, {1,0,1}, {2,1,0}, {3,0,-1}, {4,-1,0}, {5,0,2}, {6,2,1}, {7,0,-2}, {8,-2,-1}, {9,-1,2},
        {10,2,2}, {11,1,-2}, {12,-2,-2}, {13,1,2}, {14,3,1}, {15,-1,-2}, {16,-3,-1}, {17,0,3}, {18,4,4}, {19,0,-3},
        {20,-4,-4}, {21,-1,4}, {22,4,2}, {23,1,-4}, {24,-4,-2}, {25,1,4}, {26,3,0}, {27,-1,-4}, {28,-3,0}, {29,2,3},
        {30,5,4}, {31,-2,-3}, {32,-5,-4}, {33,5,3}, {34,-5,-3}, {35,2,0}, {36,-2,0}, {37,6,3}, {38,-6,-3}, {39,5,2},
        {40,-5,-2}, {41,1,-1}, {42,-1,1}, {43,6,2}, {44,-6,-2}, {45,4,3}, {46,-4,-3}, {47,3,-1}, {48,-3,1}, {49,5,1},
        {50,-5,-1}, {51,2,-2}, {52,-2,2}, {53,5,0}, {54,-5,0}, {55,4,-4}, {56,-4,4}, {57,4,1}, {58,-4,-1}, {59,5,-3},
        {60,-5,3}, {61,6,1}, {62,-6,-1}, {63,2,-4}, {64,-2,4}, {65,7,0}, {66,-7,0}, {67,5,-1}, {68,-5,1}, {69,4,-1},
        {70,-4,1}, {71,2,-3}, {72,-2,3}, {73,7,1}, {74,-7,-1}, {75,6,-2}, {76,-6,2}, {77,4,-2}, {78,-4,2}, {79,6,-3},
        {80,-6,3}, {81,7,-1}, {82,-7,1}, {83,7,-3}, {84,-7,3}, {85,3,-2}, {86,-3,2}, {87,6,-4}, {88,-6,4}, {89,8,0},
        {90,-8,0}, {91,7,-4}, {92,-7,4}, {93,4,-3}, {94,-4,3}, {95,8,2}, {96,-8,-2}, {97,8,-2}, {98,-8,2}, {99,8,4},
        {100,-8,-4}
    };

in Kotlin this renders to:

val coordinates = arrayOf(
            intArrayOf(0, 0, 0), intArrayOf(1, 0, 1), intArrayOf(2, 1, 0), intArrayOf(3, 0, -1), intArrayOf(4, -1, 0), intArrayOf(5, 0, 2), intArrayOf(6, 2, 1), intArrayOf(7, 0, -2), intArrayOf(8, -2, -1), intArrayOf(9, -1, 2),
            intArrayOf(10, 2, 2), intArrayOf(11, 1, -2), intArrayOf(12, -2, -2), intArrayOf(13, 1, 2), intArrayOf(14, 3, 1), intArrayOf(15, -1, -2), intArrayOf(16, -3, -1), intArrayOf(17, 0, 3), intArrayOf(18, 4, 4), intArrayOf(19, 0, -3),
            intArrayOf(20, -4, -4), intArrayOf(21, -1, 4), intArrayOf(22, 4, 2), intArrayOf(23, 1, -4), intArrayOf(24, -4, -2), intArrayOf(25, 1, 4), intArrayOf(26, 3, 0), intArrayOf(27, -1, -4), intArrayOf(28, -3, 0), intArrayOf(29, 2, 3),
            intArrayOf(30, 5, 4), intArrayOf(31, -2, -3), intArrayOf(32, -5, -4), intArrayOf(33, 5, 3), intArrayOf(34, -5, -3), intArrayOf(35, 2, 0), intArrayOf(36, -2, 0), intArrayOf(37, 6, 3), intArrayOf(38, -6, -3), intArrayOf(39, 5, 2),
            intArrayOf(40, -5, -2), intArrayOf(41, 1, -1), intArrayOf(42, -1, 1), intArrayOf(43, 6, 2), intArrayOf(44, -6, -2), intArrayOf(45, 4, 3), intArrayOf(46, -4, -3), intArrayOf(47, 3, -1), intArrayOf(48, -3, 1), intArrayOf(49, 5, 1),
            intArrayOf(50, -5, -1), intArrayOf(51, 2, -2), intArrayOf(52, -2, 2), intArrayOf(53, 5, 0), intArrayOf(54, -5, 0), intArrayOf(55, 4, -4), intArrayOf(56, -4, 4), intArrayOf(57, 4, 1), intArrayOf(58, -4, -1), intArrayOf(59, 5, -3),
            intArrayOf(60, -5, 3), intArrayOf(61, 6, 1), intArrayOf(62, -6, -1), intArrayOf(63, 2, -4), intArrayOf(64, -2, 4), intArrayOf(65, 7, 0), intArrayOf(66, -7, 0), intArrayOf(67, 5, -1), intArrayOf(68, -5, 1), intArrayOf(69, 4, -1),
            intArrayOf(70, -4, 1), intArrayOf(71, 2, -3), intArrayOf(72, -2, 3), intArrayOf(73, 7, 1), intArrayOf(74, -7, -1), intArrayOf(75, 6, -2), intArrayOf(76, -6, 2), intArrayOf(77, 4, -2), intArrayOf(78, -4, 2), intArrayOf(79, 6, -3),
            intArrayOf(80, -6, 3), intArrayOf(81, 7, -1), intArrayOf(82, -7, 1), intArrayOf(83, 7, -3), intArrayOf(84, -7, 3), intArrayOf(85, 3, -2), intArrayOf(86, -3, 2), intArrayOf(87, 6, -4), intArrayOf(88, -6, 4), intArrayOf(89, 8, 0),
            intArrayOf(90, -8, 0), intArrayOf(91, 7, -4), intArrayOf(92, -7, 4), intArrayOf(93, 4, -3), intArrayOf(94, -4, 3), intArrayOf(95, 8, 2), intArrayOf(96, -8, -2), intArrayOf(97, 8, -2), intArrayOf(98, -8, 2), intArrayOf(99, 8, 4),
            intArrayOf(100, -8, -4))

which is horrible and not very readable. Any better way to do this (except loading it from a file).

Cheera,
Gem

My opinion - drop this code to resources (if possible).

Why:

  • Compilation and code analyzing of this block will work faster.
  • Philosophically this is resource. So it is better to keep these values are the resources.
  • Probably for you it is better to work with format, which can be opened at the external lightweight editor (without Kotlin intellisence, however with table-like edit suggestions).

For example you can store all data at the md file, which will have only table inside. Then:

  • This table can be reviewed at the GitHub/BitBucket tools (both supports markdown)
  • This table is separate from code (so syntax highlight is not mixed)
2 Likes

I agree with @imanushin. Large data should be moved out of code. You can represent it as text or binary. There are a lot of arguments in favor of this solution. For example, static variables are allocated in memory, while files could be loaded on-demand. Another solution is to use 1d array and split it on load.

Thank you. I know about this alternative (thats why I wrote “except loading from file”). I will think about this.

But the question stays. Is there a good way to write this in code?

the 1d array might be, what I am looking for - again it’s not exactly beautiful. But thanks for the hint.

If you need it in code, consider actually generating that code rather than using a literal. It also seems to be of a size that one-time initialisation is not a major issue to transform it from an easy to insert form to an easy to use form.

Not sure if this is what you meant, but I would probably store it as a 1D array and have a getter that returns triples from the array in a Point data class

Here is a BufferAccessor implementation, which allows to work with 1d arrays as 2d arrays: https://github.com/mipt-npm/kmath/blob/dev/kmath-core/src/commonMain/kotlin/scientifik/kmath/structures/BufferAccessor2D.kt.

In this case, I gathered that what he wanted was not a multiple dimensional array, but rather a one dimensional array of tuples. Looking at the data, the first value is a monotonically increasing integer that corresponds to the index so does not need to be in the data, so you can really just store pairs, so this would probably be a better implementation:

val coordinates = arrayOf(
    0 to 0, 0 to 1, 1 to 0, 0 to -1, -1 to 0, 0 to 2, 2 to 1, 0 to -2, -2 to -1, -1 to 2, 2 to 2,
    1 to -2, -2 to -2, 1 to 2, 3 to 1, -1 to -2, -3 to -1, 0 to 3, 4 to 4, 0 to -3, -4 to -4,
    -1 to 4, 4 to 2, 1 to -4, -4 to -2, 1 to 4, 3 to 0, -1 to -4, -3 to 0, 2 to 3, 5 to 4,
    -2 to -3, -5 to -4, 5 to 3, -5 to -3, 2 to 0, -2 to 0, 6 to 3, -6 to -3, 5 to 2, -5 to -2,
    1 to -1, -1 to 1, 6 to 2, -6 to -2, 4 to 3, -4 to -3, 3 to -1, -3 to 1, 5 to 1, -5 to -1,
    2 to -2, -2 to 2, 5 to 0, -5 to 0, 4 to -4, -4 to 4, 4 to 1, -4 to -1, 5 to -3, -5 to 3,
    6 to 1, -6 to -1, 2 to -4, -2 to 4, 7 to 0, -7 to 0, 5 to -1, -5 to 1, 4 to -1, -4 to 1,
    2 to -3, -2 to 3, 7 to 1, -7 to -1, 6 to -2, -6 to 2, 4 to -2, -4 to 2, 6 to -3, -6 to 3,
    7 to -1, -7 to 1, 7 to -3, -7 to 3, 3 to -2, -3 to 2, 6 to -4, -6 to 4, 8 to 0, -8 to 0,
    7 to -4, -7 to 4, 4 to -3, -4 to 3, 8 to 2, -8 to -2, 8 to -2, -8 to 2, 8 to 4, -8 to -4
)

If the OP doesn’t want to use Pair, they can use a different type and make their own “to”-like infix operator function that creates the type they do want