Matrix in "slash" order

23

1

Given two positive numbers N >= 2 and N <= 100 create a matrix which follows the following rules:

  • First Number starts at position [0,0]
  • Second Number starts at position [0,1]
  • Third number goes below First Number (position [1,0])
  • Following numbers goes in "slash" direction
  • Range of numbers used is [1, N1 * N2]. So, numbers goes from starting 1 to the result of the multiplication of both inputs.

Input

  • Two numbers N >= 2 and N <= 100. First number is the amount of rows, Second number the amount of columns.

Output

  • Matrix. (Can be outputted as a multidimensional array or a string with line breaks)

Example:

Given numbers 3 and 5 output:

1   2   4   7   10
3   5   8   11  13
6   9   12  14  15

Given numbers 2 and 2

1   2
3   4

Given Numbers 5 and 5

1   2   4   7   11
3   5   8   12  16
6   9   13  17  20
10  14  18  21  23
15  19  22  24  25

The shortest code in bytes wins.

Luis felipe De jesus Munoz

Posted 2018-04-24T12:33:39.973

Reputation: 9 639

Btw, is there a better name for this challenge? I dont know how to call it. – Luis felipe De jesus Munoz – 2018-04-24T12:34:31.067

2Can we use 0 indexing for any of the numbers? – Jo King – 2018-04-24T12:41:57.100

2@JoKing No. Must start at 1. – Luis felipe De jesus Munoz – 2018-04-24T12:42:58.473

5Very closely related. – AdmBorkBork – 2018-04-24T12:49:12.163

1@LuisfelipeDejesusMunoz Perhaps a better term for the order is "diagonals"? Personally, I'd call it a "zig-zag", because it reminds me of Cantor's Zig-Zag proof, but that might confusing. – mbomb007 – 2018-04-24T14:12:23.500

2@LuisfelipeDejesusMunoz anti-diagonal is the term for the other diagonal. – qwr – 2018-04-25T02:45:56.680

Answers

21

Jelly, 6 5 bytes

pSÞỤs

Try it online!

How it works

pSÞỤs  Main link. Left argument: n. Right argument: k

p      Take the Cartesian product of [1, ..., n] and [1, ..., k], yielding
       [[1, 1], [1, 2], ..., [n, k-1], [n, k]].
 SÞ    Sort the pairs by their sums.
       Note that index sums are constant on antidiagonals.
   Ụ   Grade up, sorting the indices of the sorted array of pairs by their values.
    s  Split the result into chunks of length k.

Dennis

Posted 2018-04-24T12:33:39.973

Reputation: 196 637

Damn. Mine is 200+ bytes. Can you add some explanation pls? – Luis felipe De jesus Munoz – 2018-04-24T13:21:05.063

I've edited my answer. – Dennis – 2018-04-24T13:25:02.530

3God damn it, Dennis. Also, good job. – Nit – 2018-04-24T13:35:45.370

@LuisfelipeDejesusMunoz Looks like you're not using Jelly. Some languages are verbose by default, don't worry about that. – user202729 – 2018-04-24T13:37:20.963

6

Wow, it is too "closely related". That's identical to the first link in miles' answer. Consider upvoting both. :)

– user202729 – 2018-04-24T13:56:59.123

1

I think it might be possible to do this with <atom><atom>¥þ but I can't find the right combination. oþ++þ is close but doesn't quite get there

– dylnan – 2018-04-24T17:38:14.017

Seems like this answer won. – Luis felipe De jesus Munoz – 2018-04-26T13:16:22.513

I'm a little confused on what does. So up to that point for say a matrix dim(2,3) you would have [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3]] which you sort by the sum of their pairs. I assume that the sort 1.is low to high 2. tie leaves first appearance first giving [[1, 1], [1, 2], [2, 1], [1, 3], [2, 2], [2, 3]]. Am I right up to here? What happens after this step? – akozi – 2018-04-26T14:41:40.207

1@akozi So far, so good. The indices of the sorted array are [1, 2, 3, 4, 5, 6]. sorts this array, using the key that maps 1 to [1, 1], 2 to [1, 2], 3 to [2, 1], etc. Essentially, this finds the index of each pair from the sorted-by-sums array in the sorted-lexicographically array – Dennis – 2018-04-26T14:51:30.040

So you map the numbers 1-n*k to the unsorted list based on the sorted list then split the unsorted list back into rows of length k? – akozi – 2018-04-26T15:12:03.220

@akozi Basically, yes. – Dennis – 2018-04-26T15:14:13.543

8

Python 3, 91 bytes

def f(n,k):M=[(t//k+t%k,t)for t in range(n*k)];return zip(*k*[map([M,*sorted(M)].index,M)])

Try it online!

Dennis

Posted 2018-04-24T12:33:39.973

Reputation: 196 637

7

R, 101 60 54 bytes

function(M,N)matrix(rank(outer(1:M,1:N,"+"),,"l"),M,N)

Try it online!

Thanks to @nwellnhof for the suggestion of rank

Ports Dennis' Jelly answer.

Old answer, 101 bytes:

function(M,N)matrix(unsplit(lapply(split(1:(M*N),unlist(split(x,x))),rev),x<-outer(1:M,1:N,"+")),M,N)

Try it online!

split is doing most of the work here; possibly there's a golfier algorithm but this definitely works.

Explanation:

function(M,N){
x <- outer(1:M,1:N,"+")			# create matrix with distinct indices for the antidiagonals
idx <- split(x,x)			# split into factor groups
items <- split(1:(M*N),unlist(idx))	# now split 1:(M*N) into factor groups using the groupings from idx
items <- lapply(items,rev)		# except that the factor groups are
					# $`2`:1, $`3`:2,3, (etc.) but we need
                                        # $`2`:1, $`3`:3,2, so we reverse each sublist
matrix(unsplit(items,x),M,N)		# now unsplit to rearrange the vector to the right order
					# and construct a matrix, returning the value
}

Try it online! -- you can use wrap a print around any of the right-hand sides of the assignments <- to see the intermediate results without changing the final outcome, as print returns its input.

Giuseppe

Posted 2018-04-24T12:33:39.973

Reputation: 21 077

1Can you add some explanation pls? – Luis felipe De jesus Munoz – 2018-04-24T13:36:33.280

1@LuisfelipeDejesusMunoz added. If there's anything unclear, let me know and I'll try and clarify. – Giuseppe – 2018-04-24T13:56:25.360

1rank(x,1,"f") is 2 bytes shorter than order(order(x)). – nwellnhof – 2018-04-25T11:19:14.967

@nwellnhof oh, very nice, but using rank(x,,"l") will get rid of the t as well. – Giuseppe – 2018-04-25T11:26:57.200

6

Java 10, 121 120 109 105 bytes

m->n->{var R=new int[m][n];for(int i=0,j,v=0;i<m+n;)for(j=++i<n?0:i-n;j<i&j<m;)R[j][i-++j]=++v;return R;}

-11 bytes thanks to @OlivierGrégoire.
-4 bytes thanks to @ceilingcat.

Try it online.

Explanation:

m->n->{                // Method with two integer parameters and integer-matrix return-type
  var R=new int[m][n]; //  Result-matrix of size `m` by `n`
  for(int i=0,j,       //  Index integers, starting at 0
          v=0;         //  Count integer, starting at 0
      i<m+n;)          //  Loop as long as `i` is smaller than `m+n`
    for(j=++i<n?0      //   Set `j` to 0 if `i+1` is smaller than `n`
               :i-n;   //   or to the difference between `i` and `n` otherwise
        j<i&j<m;)      //   Inner loop `j` until it's equal to either `i` or `m`,
                       //   so basically check if it's still within bounds:
      R[j][i-++j]=++v; //    Add the current number to cell `j, i-(j+1)`
  return R;}           //  Return the result-matrix

Kevin Cruijssen

Posted 2018-04-24T12:33:39.973

Reputation: 67 575

I realized this takes columns first and then rows. – Luis felipe De jesus Munoz – 2018-04-24T13:33:15.573

@Luis I think it's convention to take coordinates as x,y/width,height – Jo King – 2018-04-24T13:46:54.953

2109 bytes – Olivier Grégoire – 2018-04-25T15:23:29.460

5

J, 15 bytes

$1(+/:@;)</.@i.

-4 more bytes for this solution by miles. Thanks!

Try it online!

J, 22 19 bytes

-3 bytes thanks to FrownyFrog!

,$[:>:@/:@/:@,+/&i.

Try it online!

An implementation of Dennis' fantastic Jelly solution in J.

Explanation:

Dyadic verb, takes left and right argument (m f n)

+/&i. creates lists 0..m-1 and 0..n-1 and makes an addition table for them:

   3 +/&i. 5
0 1 2 3 4
1 2 3 4 5
2 3 4 5 6

[:>:@/:@/:@, flattens the table and grades the list twice and adds 1 to it:

   3 ([:>:@/:@/:@,+/&i.) 5
1 2 4 7 10 3 5 8 11 13 6 9 12 14 15

,$ reshapes the list back into mxn table:

   3 (-@],\[:>:@/:@/:@,+/&i.) 5
1 2  4  7 10
3 5  8 11 13
6 9 12 14 15

Galen Ivanov

Posted 2018-04-24T12:33:39.973

Reputation: 13 815

1-@],\,$ for −3 bytes. – FrownyFrog – 2018-04-24T14:18:59.720

@FrownyFrog - Of course, I feel stupid, it's so obvous now. Thank you! – Galen Ivanov – 2018-04-24T14:28:12.247

115 bytes $1(+/:@;)</.@i. with input as an array [r, c] – miles – 2018-04-24T14:38:50.407

@miles: Very cool, thanks! I tried /. but could't achieve your result :) – Galen Ivanov – 2018-04-24T18:22:01.033

4

APL+WIN, 38 or 22 bytes

Prompts for integer input column then row:

m[⍋+⌿1+(r,c)⊤m-1]←m←⍳(c←⎕)×r←⎕⋄(r,c)⍴m

or:

(r,c)⍴⍋⍋,(⍳r←⎕)∘.+⍳c←⎕

based on Dennis's double application of grade up. Missed that :(

Graham

Posted 2018-04-24T12:33:39.973

Reputation: 3 184

1Sorry for the question but is there somewhere I can test it? – Luis felipe De jesus Munoz – 2018-04-24T14:08:22.360

@Luis felipe De jesus Munoz No problem. APL+WIN is not available on line but you can test it on the Dyalog website at http://tryapl.org/ if you replace the ⎕ characters with the integers of your choice.

– Graham – 2018-04-24T14:35:01.320

4

APL (Dyalog Unicode), 14 12 bytes

{⍵⍴⍋⍋∊+/↑⍳⍵}

Try it online!

-2 thanks to ngn, due to his clever usage of ↑⍳.

Based off of Dennis's 5-byte Jelly solution.

Erik the Outgolfer

Posted 2018-04-24T12:33:39.973

Reputation: 38 134

∘.+⌿⍳¨⍵ -> +/↑⍳⍵ – ngn – 2018-05-04T09:20:31.440

@ngn Wow, that's a clever usage of combined with . – Erik the Outgolfer – 2018-05-04T12:53:07.637

4

Wolfram Language (Mathematica), 73 67 bytes

Count elements in rows above: Min[j+k,#2]~Sum~{k,i-1}

Count elements on the current row and below: Max[j-k+i-1,0]~Sum~{k,i,#}

Put into a table and add 1. Voila:

1+Table[Min[j+k,#2]~Sum~{k,i-1}+Max[j-k+i-1,0]~Sum~{k,i,#},{i,#},{j,#2}]&

Update: I realized there is a shorter way to count all the positions ahead of a normally specified position in the matrix with just one sum over two dimensions:

Table[1+Sum[Boole[s-i<j-t||s-i==j-t<0],{s,#},{t,#2}],{i,#},{j,#2}]&

Try it online!

Try it online!

Kelly Lowder

Posted 2018-04-24T12:33:39.973

Reputation: 3 225

3

05AB1E, 23 bytes

*L<DΣ¹LILâOsè}UΣXsè}Á>ô

Try it online!

Emigna

Posted 2018-04-24T12:33:39.973

Reputation: 50 798

2

Python 3, 164 bytes

from numpy import*
r=range
def h(x,y):
 a,i,k,j=-array([i//y+i%y for i in r(x*y)]),1,2,0
 while j<x+y:a[a==-j],i,k,j=r(i,k),k,k+sum(a==~j),j+1
 a.shape=x,y;return a

Try it online!

This is definitely not the shortest solution, but I thought it was a fun one.

maxb

Posted 2018-04-24T12:33:39.973

Reputation: 5 754

from numpy import* and dropping both n. is slightly shorter. Also, you can drop the space at ) for. And changing to Python 2 allows you to change return a to print a (in Python 3 it would be the same byte-count print(a)). – Kevin Cruijssen – 2018-04-24T14:25:14.610

Thanks! I should have thought of import*. I'll never beat Dennis' answer, so I'll stick to Python 3. – maxb – 2018-04-24T14:36:49.163

2

TI-Basic, 76 bytes

Prompt A,B
{A,Bdim([A]
1X
For(E,1,B+A
For(D,1,E
If D≤A and E-D<B
Then
X[A](D,E-D+1
X+1X
End
End
End
[A]

Prompts for user input and returns the matrix in Ans and prints it.

TI-Basic is a tokenized language; all tokens used here are one byte, other than [A] which is 2 bytes.

Note: TI-Basic (at least on the TI-84 Plus CE) only supports matrices up to 99x99, and so does this program.

Explanation:

Prompt A,B        # 5 bytes, prompt for user input
{A,Bdim([A]      # 9 bytes, make the matrix the right size
1X               # 4 bytes, counter variable starts at 1
For(E,1,B+A       # 9 bytes, Diagonal counter, 1 to A+B-1, but we can over-estimate since we have to check later anyway.
For(D,1,E         # 7 bytes, Row counter, 1 to diagonal count
If D≤A and E-D<B  # 10 bytes, Check if we are currently on a valid point in the matrix
Then              # 2 bytes, If so,
X[A](D,E-D+1     # 13 bytes, Store the current number in the current point in the matrix
X+1X             # 6 bytes, Increment counter
End               # 2 bytes, End dimension check if statement
End               # 2 bytes, End row for loop
End               # 2 bytes, End dimension for loop
[A]               # 2 bytes, Implicitly return the matrix in Ans and print it

pizzapants184

Posted 2018-04-24T12:33:39.973

Reputation: 3 174

2

Python 2, 93 bytes

def f(b,a):i=1;o=[];exec"if b:o+=[],;b-=1\nfor l in o:k=len(l)<a;l+=[i]*k;i+=k\n"*a*b;print o

Try it online!

Semi-Ungolfed version:

def f(b,a):
    i=1
    o=[]
    for _ in range(a*b)
        if b:
            o+=[[]]
            b-=1

        for l in o:
            if len(l)<a:
                l+=[i]
                i+=1
    print o

Rod

Posted 2018-04-24T12:33:39.973

Reputation: 17 588

2

Japt, 25 24 bytes

Hardly elegant, but gets the job done. Working with 2D data in Japt is tricky.

;N×Ç<U©Ap[] A®Ê<V©Zp°T
A

;                      // Set alternative default vars where A is an empty array.
 N×Ç                   // Multiply the inputs and map the range [0..U*V).
    <U                 // If the current item is less than the second input,
      ©Ap[]            // add a new empty subarray into A.
            A®         // Then, for each item in A,
              Ê<V      // if its length is less than the first input,
                 ©Zp°T // Add the next number in the sequence to it.
A                      // Output the results, stored in A.

I added the -Q flag in TIO for easier visualization of the results, it doesn't affect the solution.
Bit off one byte thanks to Oliver.

Try it online!

Nit

Posted 2018-04-24T12:33:39.973

Reputation: 2 667

Speaking of ×, you can replace *V with . – Oliver – 2018-04-25T00:30:54.743

1@Oliver And here I was, thinking that shortcut is handy, but not a common use case. Thanks a lot! – Nit – 2018-04-25T01:03:11.683

2

JavaScript (Node.js), 103 bytes

(a,b,e=[...Array(b)].map(_=>[]))=>f=(x=0,y=i=0)=>(x<a&y<b&&(e[y][x]=++i),x?f(--x,++y):y>a+b?e:f(++y,0))

Try it online!

l4m2

Posted 2018-04-24T12:33:39.973

Reputation: 5 985

2

Perl 6, 61 59 bytes

{($!={sort($_ Z=>1..*)>>.{*}})($!([X+] ^<<$_)).rotor(.[1])}

Try it online!

Another port of Dennis' Jelly solution.

nwellnhof

Posted 2018-04-24T12:33:39.973

Reputation: 10 037

2

Java (JDK 10), 142 131 bytes

X->Y->{var A=new int[X][Y];int E=1;for(int y=0;y<Y+X-1;y++)for(int x=0;x<X;x++){if(y-x<0|y-x>Y-1)continue;A[x][y-x]=E++;}return A;}

Try it online!

Explanation:

X->Y->{                            // Method with two integer parameters and integer-matrix return-type
    var A=new int[X][Y];           // The Matrix with the size of X and Y
    int E=1;                       // It's a counter
        for(int y=0;y<Y+X-1;y++)   // For each column plus the number of rows minus one so it will run as long as the bottom right corner will be reached
            for(int x=0;x<X;x++){  // For each row
                if(y-x<0|y-x>Y-1)  // If the cell does not exist becouse it's out of range
                    continue;      // Skip this loop cycle
                A[x][y-x]=E++;     // Set the cell to the counter plus 1
            }
    return A;                      // Return the filled Array
}

Big thank to Kevin Cruijssen because I didn't know how to run my code on tio.
Some code like the header and footer are stolen from him. -> His answer

Hille

Posted 2018-04-24T12:33:39.973

Reputation: 349

1

PHP, 115 bytes

a pretty lazy approach; probably not the shortest possible.

function($w,$h){for(;$i++<$h*$w;$r[+$y][+$x]=$i,$x--&&++$y<$h||$x=++$d+$y=0)while($x>=$w|$y<0)$y+=!!$x--;return$r;}

anonymous function, takes width and height as parameters, returns 2d matrix

try it online

Titus

Posted 2018-04-24T12:33:39.973

Reputation: 13 814

1

JavaScript (Node.js), 108 105 101 100 bytes

n=>(l=>{for(r=[];i<n*n;n*~-n/2+2>i?l++:l--*y++)for(T=y,t=l;t--;)r[T]=[...r[T++]||[],++i]})(y=i=0)||r

Try it online!

DanielIndie

Posted 2018-04-24T12:33:39.973

Reputation: 1 220

1

Attache, 45 bytes

{Chop[Grade//2<|Flat!Table[`+,1:_2,1:_],_]+1}

Try it online!

Anonymous lambda, where paramaters are switched. This can be fixed for +1 byte, by prepending ~ to the program. The test suite does this already.

Explanation

This approach is similar to the J answer and the Jelly answer.

The first idea is to generate a table of values:

Table[`+,1:_2,1:_]

This generates an addition table using ranges of both input parameters. For input [5, 3], this gives:

A> Table[`+,1:3,1:5]
 2 3 4 5 6
 3 4 5 6 7
 4 5 6 7 8

Then, we flatten this with Flat!:

A> Flat!Table[`+,1:3,1:5]
[2, 3, 4, 5, 6, 3, 4, 5, 6, 7, 4, 5, 6, 7, 8]

Using the approach in the J answer, we can grade the array (that is, return indices of sorted values) twice, with Grade//2:

A> Grade//2<|Flat!Table[`+,1:3,1:5]
[0, 1, 3, 6, 9, 2, 4, 7, 10, 12, 5, 8, 11, 13, 14]

Then, we need to chop the values up correctly, as in the Jelly answer. We can cut every _ elements to do this:

A> Chop[Grade//2<|Flat!Table[`+,1:3,1:5],5]
 0 1  3  6  9
 2 4  7 10 12
 5 8 11 13 14

Then, we just need to compensate for the 0-indexing of Attache with +1:

A> Chop[Grade//2<|Flat!Table[`+,1:3,1:5],5]+1
 1 2  4  7 10
 3 5  8 11 13
 6 9 12 14 15

And thus we have the result.

Conor O'Brien

Posted 2018-04-24T12:33:39.973

Reputation: 36 228

1

Python 3, 259 bytes

So I did this a weird way. I noticed that there were two patterns in the way the array forms.

The first is how the top rows pattern has the difference between each term increasing from 1 -> h where h is the height and l is the length. So I construct the top row based on that pattern

For a matrix of dim(3,4) giving a max RoC = 3 We will see the top row of the form

1, (1+1), (2+2), (4+3) = 1, 2, 4, 7

Suppose instead that the dim(3,9) giving a max RoC = 3 we will instead see a top row of

`1, (1+1), (2+2), (4+3), (7+3), (10+3), (13+3), (16+3), (19+3) = 1, 2, 4, 7, 10, 13, 16, 19, 22

The second pattern is how the rows change from one another. If we consider the matrix:

1   2   4   7   11
3   5   8   12  16
6   9   13  17  20
10  14  18  21  23
15  19  22  24  25

and subtract each row from the row below (ignoring the extra row) we get

2 3 4 5 5
3 4 5 5 4
4 5 5 4 3
5 5 4 3 2

Upon seeing this matrix we can notice this matrix is the sequence 2 3 4 5 5 4 3 2 where by each row is 5 terms of this pattern shifted by 1 for each row. See below for visual.

         |2 3 4 5 5| 4 3 2
       2 |3 4 5 5 4| 3 2
     2 3 |4 5 5 4 3| 2
   2 3 4 |5 5 4 3 2|

So to get the final matrix we take our first row we created and output that row added with the 5 needed terms of this pattern.

This pattern will always have the characteristics of beginning 2-> max value and ending max value -> 2 where the max value = min(h+1, l) and the number of times that the max value will appear is appearances of max = h + l -2*c -2 where c = min(h+1, l) - 2

So in whole my method of creating new rows looks like

1  2  3  7  11 +      |2 3 4 5 5|4 3 2  = 3  5  8  12 16

3  5  8  12 16 +     2|3 4 5 5 4|3 4 2  = 6  9  13 17 20

6  9  13 17 20 +   2 3|4 5 5 4 3|4 2    = 10 14 18 21 23

10 14 18 21 23 + 2 3 4|5 5 4 3 2|       = 15 19 22 24 25

Relevant code below. It didn't end up being short but I still like the method.

o,r=len,range
def m(l,h):
 a,t=[1+sum(([0]+[x for x in r(1,h)]+[h]*(l-h))[:x+1]) for x in r(l)],min(l,h+1);s,c=[x for x in r(2,t)],[a[:]]
 for i in r(h-1):
  for j in r(o(a)):
   a[j]+=(s+[t]*(l+h-2*(t-2)-2)+s[::-1])[0+i:l+i][j]
  c+=[a[:]]
 for l in c:print(l)

Try it online!

akozi

Posted 2018-04-24T12:33:39.973

Reputation: 551

0

Japt, 20 bytes

õ ïVõ)ñx
£bYgUñ¹ÄÃòV

Try it

Shaggy

Posted 2018-04-24T12:33:39.973

Reputation: 24 623