28
\$\begingroup\$

Write a program or function that, given an integer n, construct an array with n dimensions of n length, where each element is an identifier of its own coordinates. That is, starting with one array, populate it with n arrays, where each of those contain n more arrays, up to a depth of n-1. The elements of the deepest arrays are the coordinates describing where they are in the full array.

Some examples in case my explanation was confusing.

n = 1

["1"]

n = 2

[
 ["11", "12"],
 ["21", "22"]
]

n = 3

[
  [
    ["111","112","113"],
    ["121","122","123"],
    ["131","132","133"]
  ],
  [
    ["211","212","213"],
    ["221","222","223"],
    ["231","232","233"]
  ],
  [
    ["311","312","313"],
    ["321","322","323"],
    ["331","332","333"]
  ]
]

Here, "321" means it is the 1st element of the 2nd element of the 3rd array.

Rules:

  • Coordinates and dimension (n) can be either 0 or 1 indexed
  • You may assume n is single digit, below 10 for both indexing options to prevent ambiguous outputs
  • IO is flexible.
    • In particular, coordinates can be arrays, strings etc. as long as they are clear. "321" => [3,2,1]
    • Output can be integers in base 10 with or without leading zeroes.
    • Coordinates can be in reverse order if you wish, as long as it is consistent. "321" => "123"
    • Output doesn't necessarily have to be an array structure in your language. As long as there's clear distinct markers for the start of an array, end of an array and for separating elements.
    • The output for n=1 can just be 1
    • If your output is atypical, make sure to explain the format.
  • This is so the shortest solution in each language wins!
\$\endgroup\$
15
  • \$\begingroup\$ Sandbox (deleted) \$\endgroup\$
    – Jo King
    Commented Jul 5, 2018 at 0:49
  • \$\begingroup\$ I was having trouble writing this in Haskell, before I realized that the type system makes it impossible. \$\endgroup\$
    – Wheat Wizard
    Commented Jul 5, 2018 at 0:58
  • \$\begingroup\$ @CatWizard: You could always define a new data structure to get around that, eg. data L a = L [L a] | E a. \$\endgroup\$ Commented Jul 5, 2018 at 2:35
  • 2
    \$\begingroup\$ Related. \$\endgroup\$
    – Adám
    Commented Jul 5, 2018 at 5:29
  • 1
    \$\begingroup\$ @ToddSewell You can't have a function whose type depends on the input. This function could have type Int -> [String] or Int -> [[String]] and so on, depending on what the input is \$\endgroup\$
    – H.PWiz
    Commented Jul 6, 2018 at 1:27

15 Answers 15

19
\$\begingroup\$

Dyalog APL, 5 3 bytes

⍳⍴⍨

-2 bytes thanks to FrownyFrog

Try it online!

gives all the indices given the shape of an array. e.g. 2 3.
reshapes the right arg to be the size of the left arg. makes both be the right arg.

\$\endgroup\$
0
10
\$\begingroup\$

Python 3, 56 bytes

f=lambda n,*l:len(l)//n*l or[f(n,*l,k)for k in range(n)]

Try it online!

Mr. Xcoder saved 2 bytes switching to Python 3 for starred unpacking.

\$\endgroup\$
1
  • 3
    \$\begingroup\$ If you switch to Python ≥3.5, f=lambda n,*l:len(l)//n*l or[f(n,*l,k)for k in range(n)] works for 56 bytes. \$\endgroup\$
    – Mr. Xcoder
    Commented Jul 5, 2018 at 6:19
9
\$\begingroup\$

Wolfram Language (Mathematica), 32 22 bytes

-10 bytes thanks to @alephalpha

Array[List,#~Table~#]&

Try it online!

\$\endgroup\$
0
6
\$\begingroup\$

J, 18 bytes

,"1/^:(]{:)~@,.@i.

Try it online!

Iterative solution, no built-in cartesian product. This is what peak J looks like.

                       input                                    2
                i.     range                                 0, 1
             ,.@       reshape each element
                       into a one-dimensional array        [0],[1]   (A)
    ^:(]{:)            (input−1) times...             (1 iteration)
,"1/       ~@             prepend the contents of each 1d array in A    |
                          to every 1d array from the previous iteration,|  
                          assembling the results for each A[n] into     |!CANTEXPLAINTHIS!
                          a larger array                                |
                                                         [ [0,0],       |
                                                           [0,1] ],     |
                                                         [ [1,0],       |
                                                           [1,1] ]      |
\$\endgroup\$
1
  • \$\begingroup\$ At first the higher byte count put me off, but this truly is beautiful J \$\endgroup\$
    – Jonah
    Commented Jul 6, 2018 at 2:13
6
\$\begingroup\$

Jelly, 8 7 bytes

ṗ³s³$³¡

Try it online!

Explanation

Use argument 2 as an example.

ṗ³s³$³¡   
ṗ        Cartesian power with power
 ³       2 (the argument). Autoranges the left arg.
         Yields [[1,1],[1,2],[2,1],[2,2]]
    $³¡  Do 2 times:
  s³     Split into segments of length 2. 
         This last step molds the array of indices into the proper shape.

If ¡ didn't vary it's right argument over iterations for dyads then this would be 4 bytes: ṗs³¡

\$\endgroup\$
3
  • \$\begingroup\$ This looks like a full program to me. Are you sure the output (STDOUT) for 1 is valid? \$\endgroup\$ Commented Jul 5, 2018 at 9:36
  • \$\begingroup\$ @EriktheOutgolfer I'm okay with the output for 1 \$\endgroup\$
    – Jo King
    Commented Jul 5, 2018 at 10:20
  • \$\begingroup\$ @JoKing But, in this case, there aren't "clear distinct markers for the start of an array, end of an array". Do you want to edit the question? (a lot of answers don't actually contain them) \$\endgroup\$ Commented Jul 5, 2018 at 11:00
5
\$\begingroup\$

J, 13 bytes

[:{[;/@$,:@i.

Try it online!

Interesting this is so much longer than the APL answer (though that may be my inability to see a better translation)

explanation

[: { [ ;/@$ ,:@i.


     [                NB. the argument
            ,:@i.     NB. range 0..arg, considered as one item: ,: is "itemize" 
          $           NB. repeat the right range the left number of times
       ;/@            NB. and then put boxes around them. so, eg, if we had
                      NB. an arg of 3, now we have the list of boxes 
                      NB. [0 1 2][0 1 2][0 1 2]
[: {                  NB. { is "Catalog", it creates the cartesian product
                      NB. in exactly the format we desire.
\$\endgroup\$
4
  • 1
    \$\begingroup\$ A better(?) translation \$\endgroup\$
    – FrownyFrog
    Commented Jul 5, 2018 at 9:50
  • \$\begingroup\$ @FrownyFrog Using a hook to avoid #.inv is very clever, +1. \$\endgroup\$
    – cole
    Commented Jul 5, 2018 at 12:46
  • \$\begingroup\$ @FrownyFrog Now that I've looked at your "count up in different bases" solution, I think the approach is different enough that you should add it as another post yourself. It's a very nice solution. \$\endgroup\$
    – Jonah
    Commented Jul 6, 2018 at 3:58
  • \$\begingroup\$ Jonah, @cole thank you \$\endgroup\$
    – FrownyFrog
    Commented Jul 6, 2018 at 5:06
5
\$\begingroup\$

MATLAB, 92 89 55 bytes

I have a different answer having re-read the rules of the challenge, but I'll leave the previous attempt below as it's different and still fun to look at.

reshape(string(dec2base(0:n^n-1,n+(n<2))),[~(1:n)+n 1])

Explanation

                        0:n^n-1                        % [0,1,...,n^n-1]
               dec2base(       ,n+(n<2))               % Put into base n (base 2 if n=1)
        string(                         )              % Convert to strings
                                          [~(1:n)+n 1] % Dimension array [n,n,...,n] (length n)
reshape(                                 ,            )% Use dim array to reshape

This outputs an n-dimensional array of strings which are 0 indexed.

Previous Answer (89 bytes)

My first golf! This can likely be reduced more but I thought I'd post what I've got.

x=(1:n)';for d=2:n;y=((1:n)*10^(d-1));o=[];for p=1:nnz(y);o=cat(d,o,(x+y(p)));end;x=o end

Explanation

x=(1:n)';                       % Create array x=[1,2,...n]'
for d=2:n                       % d for dimension
    y=((1:n)*10^(d-1));         % Creates an array for each d where
                                %   y=[10,20,30,...] for n=2
                                %   y=[100,200,...] for n=3 etc.
    o=[];                       % o for output
    for p=1:nnz(y)              % For each value of y
        o=cat(d,...             % Concatenate in the dth dimension:
            o,...               % - The current output
            x+y(p));            % - The sum of
                                %   - The array from the last dimension
                                %   - The current value in y (e.g. 100)
    end
    x=o                         % Send the output to x for the next loop
end

Outputs x at the end to give solution

Similar to the other MATLAB post, the output is an n-dimensional array, except it uses numbers to display the coordinates. It works for any value, although because loops are bad in MATLAB it begins to slow down significantly around n = 8.

Edit: -2 bytes thanks to Luis Mendo. Also removed final semicolon to print the output.

\$\endgroup\$
2
  • 4
    \$\begingroup\$ Welcome to PPCG! \$\endgroup\$
    – Shaggy
    Commented Jul 5, 2018 at 12:47
  • \$\begingroup\$ I think you can replace length by nnz to save a few bytes. Also, as per PPCG rules, the code has to produce some actual output, typically by displaying it in STDOUT (it's not enough to have the output stored in a variable), or it has to be a function that returns the output \$\endgroup\$
    – Luis Mendo
    Commented Jul 5, 2018 at 13:47
5
\$\begingroup\$

Rust, 201 176 167 166 154 bytes

enum L{S(String),L(Vec<L>)}fn
h(n:u8,d:u8,s:&str)->L{if
d<1{L::S(s.into())}else{L::L((0..n).map(|i|h(n,d-1,&format!("{}{}",s,i))).collect())}}|n|h(n,n,"")

Try it online!

The output type is a sum type with two variants as the language is strictly typed. It can be either L, which is a list type containing this sum type or S which is a result type (a string). The result can look like this.

L::L([
 L::L([ L::S("00"), L::S("01") ]),
 L::L([ L::S("10"), L::S("11") ]),
])

Also, reformatted using rustfmt:

enum L {
    S(String),
    L(Vec<L>),
}
fn h(n: u8, d: u8, s: &str) -> L {
    if d < 1 {
        L::S(s.into())
    } else {
        L::L(
            (0..n)
                .map(|i| h(n, d - 1, &format!("{}{}", s, i)))
                .collect(),
        )
    }
}
|n| h(n, n, "")
\$\endgroup\$
4
\$\begingroup\$

R, 102 bytes

function(n,m=array(T,rep(n,n)))`if`(n<2,'1',{m[]=apply(which(m,T)[,`[<-`(1:n,1:2,2:1)],1,toString);m})

Try it online!

  • 1-indexed, reversed
  • unfortunately R stores matrix by column, otherwise we could go down to 73 bytes
  • -9 bytes saved thanks to @Giuseppe suggestion to use which array indexing
\$\endgroup\$
2
  • \$\begingroup\$ your 76 byte answer could be 73 bytes which is how I implemented it before checking to see if there was already an R answer. You might be able to change some of the approach, though? Not entirely sure. \$\endgroup\$
    – Giuseppe
    Commented Jul 5, 2018 at 13:23
  • 1
    \$\begingroup\$ @Giuseppe: array indexing of which is what I was looking for, thanks ! Saved 9 bytes \$\endgroup\$
    – digEmAll
    Commented Jul 5, 2018 at 13:40
4
\$\begingroup\$

Java 10, 144 bytes

The solution is method f. It produces a string representation of the array.

String h(int n,int d,String s){if(d<1)return s;var r="[";for(int i=0;i++<n;)r+=h(n,d-1,s+i)+",";return r+"]";}String f(int n){return h(n,n,"");}

Try It Online

Ungolfed

String h(int n, int d, String s) {
    if (d < 1)
        return s;
    var r = "[";
    for (int i = 0; i++ < n;)
        r += h(n, d - 1, s + i) + ",";
    return r + "]";
}
String f(int n) {
    return h(n, n, "");
}

Acknowledgments

\$\endgroup\$
1
  • 1
    \$\begingroup\$ In Java 10, you could replace Object[] with var. Also, I think this else block is unnecessary, as you have return in if block. \$\endgroup\$
    – null
    Commented Jul 5, 2018 at 19:00
3
\$\begingroup\$

05AB1E, 7 bytes

LsãsGsô

Try it online!

Explanation

L          # push range [1 ... input]
 sã        # input repeated cartesian products of the list
   sG      # input - 1 times do:
     sô    # split into input parts
\$\endgroup\$
3
\$\begingroup\$

JavaScript (Node.js), 62 60 58 bytes

f=(n,i=n,s='')=>i?[...Array(n)].map((_,j)=>f(n,i-1,s+j)):s

Try it online! Output is 0-indexed. Edit: Saved 2 bytes thanks to @JoKing and a further 2 bytes thanks to @Arnauld.

\$\endgroup\$
0
3
\$\begingroup\$

MATLAB, 116 108 104 bytes

I feel like there must be a shorter way to do this, given MATLAB's affinity toward multi-dimensional matrices... Thanks to Luis for the 4 bytes from some short-handing

a=~(1:n)+n;c=cell(1,n);[c{:}]=ind2sub(a,1:n^n);reshape(arrayfun(@(varargin)[varargin{:}],c{:},'un',0),a)

Explanation

% For using twice, define the array of dimension sizes [n, n, .., n]
a=~(1:n)+n;
% To group variable number of outputs from ind2sub into a cell array
c=cell(1,n);   
% Convert linear indices to self-describing coordinates
[c{:}]=ind2sub(a,1:n^n);     
% reshape to make it the n-dimensional array
% arrayfun to loop over the numerous ind2sub outputs simultaneously
% varargin and {:} usage to account for various numbers of inputs
reshape(arrayfun(@(varargin)[varargin{:}],c{:},'uni',0),a)

The output is an n-dimensional cell array, where each element is an array of the coordinate values. Works for any n without ambiguity because of the numeric array output, so long as an n^(n+1) element array can be stored in RAM!

\$\endgroup\$
0
3
\$\begingroup\$

Charcoal, 26 bytes

Nθ≔EXθθ⪫⪪◧⍘ιθθ ¦0υFθ≔⪪υθυυ

Try it online! Link is to verbose version of code. Explanation:

Nθ

Input n.

≔EXθθ⪫⪪◧⍘ιθθ ¦0υ

Generate all nⁿ n-digit numbers in base n.

Fθ≔⪪υθυ

Split them n times into an n-dimensional array where each dimension is of size n.

υ

Print the array. The default output format is each element on its own line, then each block of n lines is terminated by a blank line, then each block of n blocks of n lines is terminated by a second blank line, and so on up to n-1 blank lines at the top level.

\$\endgroup\$
2
\$\begingroup\$

Jelly, 7 bytes

ṗṁẋ`ŒṬ$

Try it online!

\$\endgroup\$

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.