Create a pyramidal matrix

23

1

A pyramidal matrix is a square matrix where all numbers increase or decrease from the center point, like the two matrices below:

1  1  1  1  1
1  2  2  2  1
1  2  3  2  1
1  2  2  2  1
1  1  1  1  1

Or:

3  3  3  3  3
3  2  2  2  3
3  2  1  2  3
3  2  2  2  3
3  3  3  3  3

Given a non-zero integer n, create a pyramidal matrix where the numbers goes from 1 to n either in increasing order (if n<0), or decreasing order (if n>0) from the center. If n is even, then there will be 4 center numbers (see the examples).

As always:

  • Optional input and output format
    • Number of spaces, delimiter etc. is optional

Test cases:

1
1

-1
1

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

-5
5  5  5  5  5  5  5  5  5
5  4  4  4  4  4  4  4  5
5  4  3  3  3  3  3  4  5
5  4  3  2  2  2  3  4  5
5  4  3  2  1  2  3  4  5
5  4  3  2  2  2  3  4  5
5  4  3  3  3  3  3  4  5
5  4  4  4  4  4  4  4  5
5  5  5  5  5  5  5  5  5

2
1  1  1  1
1  2  2  1
1  2  2  1
1  1  1  1

-2
2  2  2  2
2  1  1  2
2  1  1  2
2  2  2  2

-4
4  4  4  4  4  4  4  4
4  3  3  3  3  3  3  4
4  3  2  2  2  2  3  4
4  3  2  1  1  2  3  4
4  3  2  1  1  2  3  4
4  3  2  2  2  2  3  4
4  3  3  3  3  3  3  4
4  4  4  4  4  4  4  4

Stewie Griffin

Posted 2016-09-22T15:10:03.533

Reputation: 43 471

10Why is the even case different from the odd case? There is no reason why the matrices can't all follow the exact same pattern. – Greg Martin – 2016-09-22T16:32:23.387

2Because the input was supposed to be the length of the side wall, in which case there's a difference between odd and even. I decided to go for the maximum value instead, but kept the odd and even difference there. It might seem strange, and might not be a good explanation, but it's the explanation for why there's a difference. :-) – Stewie Griffin – 2016-09-22T17:20:09.433

2Can we assume -10 < n < 10? – Titus – 2016-09-22T18:43:45.833

2It's ok if it doesn't look like a perfect square, as long as it it's one numerically speaking. If rows with many 10s are wider that those with few 10s then that's ok... – Stewie Griffin – 2016-09-22T19:52:57.860

Answers

5

Jelly, 18 17 bytes

|1ŒḄfR«þ`
AÇạẋ¡CG

Try it online! or verify all test cases.

How it works

|1ŒḄfR«þ`  Helper link. Argument: k (positive integer)

|1         Take the bitwise OR with 1. This increments k if it is even.
  ŒḄ       Bounce; yield [1, 2, ..., k | 1, ..., 2, 1].
    fR     Filter range; remove elements not in [1, ..., k] from the array.
           This results in [1, 2, ..., k, ..., 2, 1] if k is odd and in
           [1, 2, ..., k, k, ..., 2, 1] if k is even.
        `  Pass the last return value as left and right argument to:
      «þ     Minimum table; take the minimum of each pair of elements in the
             generated array, returning a 2D array.


AÇạẋ¡CG      Main link. Argument: n

A            Take the absolute value of n.
 Ç           Call the helper link on the result.
     C       Complement; yield 1 - n.
    ¡        Conditional application:
   ẋ           If repeating the return value of Ç 1 - n times results in a non-
               empty array, i.e., if n < 1:
  ạ              Take the absolute differences of the generated integers and 1 - n.
      G      Grid; join columns by spaces, rows by linefeeds.

Dennis

Posted 2016-09-22T15:10:03.533

Reputation: 196 637

7

Python 2, 109 99 98

n=input()
r=range(1,abs(n)+1)
l=r+r[~n|-2::-1]
for j in l:print[abs((n<0)*~-n+min(i,j))for i in l]

Create list

l = [1,2,3,4,5,4,3,2,1]

and play with it a little.


edit: new way of creating list + thx Lynn for two bytes

pacholik

Posted 2016-09-22T15:10:03.533

Reputation: 490

If n is even, then there will be 4 center numbers – Rod – 2016-09-22T18:22:26.410

@Rod No there won't. What makes you think so? – pacholik – 2016-09-22T18:25:32.630

3this is one of the rules – Rod – 2016-09-22T18:28:12.090

@Rod Oh. Just few minutes ago. Edited. – pacholik – 2016-09-22T18:35:13.400

It may be a new rule; but it was always there in the examples. ;) – Titus – 2016-09-22T18:44:41.707

2It isn't new, just not highlighted :c – Rod – 2016-09-22T18:46:11.337

min(0,n-1)(n<0)*~-n for one more! – Lynn – 2016-09-22T19:12:10.307

I´m pertty certain that Lynn´s hint won´t work on every machine. – Titus – 2016-09-23T12:05:32.040

7

EXCEL: 126 bytes

=MAX(MIN(MIN(CELL("row",RC)-1,CELL("col",RC)-1),MIN(((ABS(R1C1)-1)*2+3)-CELL("row",RC),((ABS(R1C1)-1)*2+3)-CELL("col",RC))),0)

Try it online*

Note: this answer uses R1C1 Notation. If you're going to try this yourself. you need to turn that on in Excel options.

the formula given needs to be in every cell present beyond (2,2). Put your desired pyramid size into (1,1).

quick screen-cap of the formula in action:
enter image description here

Here is an Additional picture of some fun with conditional formatting!

*It takes a very long time to update, currently.

user56309

Posted 2016-09-22T15:10:03.533

Reputation:

This doesn't handle the negative cases or the even cases properly. Also you can shorten the code to =MAX(MIN(MIN(ROW()-1,COLUMN()-1),MIN(((ABS(A1)-1)*2+3)-ROW(),((ABS(A1)-1)*2+3)-COLUMN())),0) which is 92 bytes. It still doesn't handle the cases though and formula can't be dragged across since the cell reference isn't locked. – gtwebb – 2016-09-22T21:37:53.753

1More golfing same issues though. =MEDIAN(MIN(ROW()-1,COLUMN()-1),ABS(A1)*2+1-MAX(ROW(),COLUMN()),0) – gtwebb – 2016-09-22T21:49:18.040

@gtwebb thanks for telling me. I'll have to fix – None – 2016-09-22T22:00:22.160

-1. This doesn't work. It doesn't handle negative input. It doesn't handle even input. If you're putting in this formula in every applicable cell, you either need a Range or you need a heck of a lot more than 126 bytes. – AdmBorkBork – 2016-09-23T19:10:08.440

6

MATL, 26 24 bytes

oXyG|to-:"TTYaQ]G0<?G+q|

Try it online! Or verify all test cases (slightly modified code to serve as test suite).

Explanation

The code first builds the output array assuming positive input n. The array is initiallized as 1 for odd input or as the empty array for even input (this is created as an identity matrix with size equal to the parity of the input). Then the following is repeated n times for even input, and n-1 times for odd input: extend the array with a frame containing 0, and add 1 to all elements.

For example, the steps for input n are:

  • Initial array:

    1
    
  • Extend with frame:

    0 0 0
    0 1 0
    0 0 0
    
  • Add 1:

    1 1 1
    1 2 1
    1 1 1
    
  • Extend with frame:

    0 0 0 0 0
    0 1 1 1 0
    0 1 2 1 0
    0 1 1 1 0
    0 0 0 0 0
    
  • Add 1:

    1 1 1 1 1
    1 2 2 2 1
    1 2 3 2 1
    1 2 2 2 1
    1 1 1 1 1
    

This gives the correct output for positive input. If the input is negative, the array needs to be modified by adding the input minus 1 and taking the absolute value:

    3 3 3 3 3
    3 2 2 2 3
    3 2 1 2 3
    3 2 2 2 3
    3 3 3 3 3

You can watch the array growing (modified code to show intermediate steps) at MATL Online! The interpreter is still a beta. If it doesn't work press "Run" again or reload the page.

Commented code

o        % Take input implicitly and push 0 if even or 1 if odd
Xy       % Identity matrix of that size. Gives either 1 or empty array
G|       % Absolute value of input
to-      % Subtract 1 if odd
:"       % For loop: repeat that many times
  TTYa   %   Add a frame of zeros in the two dimensions
  Q      %   Add 1 to all elements
]        % End for
G        % Push input again
0>       % is it negative?
?        % If so
  G      %   Push input again
  +      %   Add
  q      %   Subtract 1
  |      %   Absolute value
         % End if implicitly
         % Display implicitly

Luis Mendo

Posted 2016-09-22T15:10:03.533

Reputation: 87 464

I see you reused the code from the animation question. Awesome! Funny part is, this code would also still win in that question, even though it's longer than your other version ;). – Magic Octopus Urn – 2016-09-22T19:15:38.567

1@carusocomputing Yes, it's similar: duplicate, display, pause 1 second, clear output :-) – Luis Mendo – 2016-09-22T19:18:07.713

Also, not sure why, but any input above 14 stops at 14. Cancel that, it's a limitation of the online console "Operation timed out". – Magic Octopus Urn – 2016-09-22T19:18:41.033

@carusocomputing The error says "operation time out". I guess it just takes too long for the interpreter. Try reducing the pause to say .2 seconds

– Luis Mendo – 2016-09-22T19:20:34.417

@carusocomputing Yes that's the timeout on the online interpreter. We currently limit jobs to 30 seconds. As Luis suggests, you can decrease the pause time – Suever – 2016-09-22T19:24:25.533

3

Python 2.7: 123 122 120 Bytes

probs can still save a few bytes...

from numpy import*
n=input()
N=abs(n)
e=N*2-N%2
a=ones([e,e])
for i in range(N):a[i:e-i,i:e-i]=(i+1)*(n>0)or-n-i
print a

edit1: N=abs(n) to save 1 byte

edit2: (i+1)*(n>0)or-n-i to save 2 bytes

Aaron

Posted 2016-09-22T15:10:03.533

Reputation: 1 213

3

Haskell, 119 113 110 104 102 101 bytes

f x|(h,t)<-splitAt(mod x 2)$[x,x-1..1]++[1.. -x]=foldl(\m n->(n#)<$>(n<$m)#m)[[y]|y<-h]t
x#y=x:y++[x]

Returns the matrix as a list of lists of integers, for example: f 2 -> [[1,1,1,1],[1,2,2,1],[1,2,2,1],[1,1,1,1]].

How it works:

            [x,x-1..1]++[1.. -x]      -- make list from x down to 1 followed by
                                      -- 1 to (-x). One of the sublists will be
                                      -- empty. The resulting list contains the
                                      -- numbers of the pyramid from inside to out.
   (h,t)<-splitAt(mod x 2)            -- bind h to the first element if x is odd
                                      -- or to the empty list if x is even
                                      -- bind t to the rest (tail or full list)

foldl (     ) [[y]|y<-h] t            -- fold the following function into t with a
                                      -- starting value of [] if x is even or
                                      -- [[h]] if x is odd

   \m n ->                            -- the current matrix m with the next number
                                      -- n is transformed into a new matrix:

               (n#)<$>(n<$m)#m        -- prepend and append a n to 
                                      -- m prepended and append by a line of n's

x#y=x:y++[x]                          -- helper function to prepend and append an
                                      -- element x to a list y

nimi

Posted 2016-09-22T15:10:03.533

Reputation: 34 639

2

Perl, 175 bytes

Includes 1 bytes for -p.

($t,$v,$w)=($_,(abs)x2);$k=$_.$k for 1..$v;map{$r.=$_ for(@v=1..$_-1),$_ x(2*$v---$w%2),reverse@v;$r.=$/}1..$v;$_=$r.~~reverse$r;eval"y/1-$w/$k/"if$t<0;$w%2&&s/

.*//||s;

;

(There is a trailing newline that I don't know how to show with the markdown, but you need it).

Needs -p as well as -M5.010 or -E to run :

perl -pE '($t,$v,$w)=($_,(abs)x2);$k=$_.$k for 1..$v;map{$r.=$_ for(@v=1..$_-1),$_ x(2*$v---$w%2),reverse@v;$r.=$/}1..$v;$_=$r.~~reverse$r;eval"y/1-$w/$k/"if$t<0;$w%2&&s/

.*//||s;

;
' <<< 5

Damn, this is too long... I'll try some other approaches when I have some time.

Dada

Posted 2016-09-22T15:10:03.533

Reputation: 8 279

Why do You use eval? – Titus – 2016-09-22T18:41:24.747

@Titus Because y/// doesn't interpolate, so is use the double quotes to interpolate $w and $k, then eval to execute y///. – Dada – 2016-09-22T18:44:34.713

2

Python 2, 109 bytes

n=input()
a=abs(n)
s=a*2-a%2
r=range(s)
for y in r:print[(min,max)[n<0](x+1,s-x,y+1,s-y)-(n<0)*s/2for x in r]

Lynn

Posted 2016-09-22T15:10:03.533

Reputation: 55 648

2

J, 29 26 bytes

1+**[:<./~**i.,2&|1&}.i.@-

Usage

   f =: 1+**[:<./~**i.,2&|1&}.i.@-
   f 1
1
   f _1
1
   f 2
1 1 1 1
1 2 2 1
1 2 2 1
1 1 1 1
   f _2
2 2 2 2
2 1 1 2
2 1 1 2
2 2 2 2
   f 3
1 1 1 1 1
1 2 2 2 1
1 2 3 2 1
1 2 2 2 1
1 1 1 1 1
   f _3
3 3 3 3 3
3 2 2 2 3
3 2 1 2 3
3 2 2 2 3
3 3 3 3 3

Explanation

The range i. verb outputs [0, 1, ..., n-1] for positive n and [n-1, n-2, ..., 0] for negative n which is useful here.

1+**[:<./~**i.,2&|1&}.i.@-  Input: integer n
                         -  Negate n
                      i.@   Creates range for -n
               2&|          Take n modulo 2, returns 0 or 1
                  1&}.      If n is odd, drop the first value from the range for -n
                            Else do nothing and pass it unmodified
              ,             Append it to
            i.              The range for n
          *                 Get the sign of n
           *                Multiply elementwise with the joined ranges
    [:<./~                  Form a table of the minimum values of the range
  *                         Get the sign of n
   *                        Multiply elementwise with the joined ranges
1+                          Add 1 to each and return

miles

Posted 2016-09-22T15:10:03.533

Reputation: 15 654

2

Mathematica, 78 bytes

Abs[Fold[ArrayPad[#,1,#2]&,Table[0,#,#]&@Mod[#,2,1],Range[Abs@#-1]]+1~Min~-#]&

Explanation

Table[0,#,#]&@Mod[#,2,1]

Make initial matrix: 1x1 if odd, 2x2 if even.

Range[Abs@#-1]

Generate a list from 1 to abs(input) - 1.

Fold[ArrayPad[#,1,#2]&, ..., ...]

Pad the initial array using the aforementioned list.

... +1~Min~-#

Add 1 or -input, whichever is smaller.

Abs

Apply absolute value to the entire matrix.

JungHwan Min

Posted 2016-09-22T15:10:03.533

Reputation: 13 290

1

PHP, 177 157 bytes

for($y=-$n=abs($z=$argv[1])+1;++$y<$n;)if($y&&($n&1||$y-1)){for($x=-$n;++$x<$n;)if($x&&($n&1||$x-1)){$v=max(abs($x),abs($y));echo$z<0?$v:$n-$v," ";}echo"
";}

run with php -r '<code>

loops through rows and columns, prints the values depending on their distance to the center.

  • $n=abs($z)+1: The +1 saves a couple of +1 and -1 in later expressions
  • loops go from -$n+1 (pre-increment in the condition!) to $n-1 (-abs($z) to abs($z))
  • line/column 0 (and for odd $n: 1) are skipped
    ($n&1 is true for even columns here! Remember the +1?)
  • The printing for positive $z also benefits from the +1.

Titus

Posted 2016-09-22T15:10:03.533

Reputation: 13 814

1

Haskell, 191 183 173 169 168 bytes

r=reverse;m=map
x!y=(((++)<*>(x.r)).).zipWith(++).m y
g n|n<0=m(m$abs.((n-1)+)).g$abs n|1<2=[id!id,tail!init]!!mod n 2=<<m r$r$m(\x->(x<$[1..x])++[x+1..n])[1..n]
g.(0-)

Usage:

mapM_ print $ (g.(0-)) 3

[1,1,1,1,1]
[1,2,2,2,1]
[1,2,3,2,1]
[1,2,2,2,1]
[1,1,1,1,1]

Thanks to nimi for 2 10 20 24 bytes!

BlackCap

Posted 2016-09-22T15:10:03.533

Reputation: 3 576

1negate is (0-) – nimi – 2016-09-22T20:46:43.807

1You can change f to [id!id,tail!init]!!mod n 2 and then inline it into g and use the 1<2 guard to bind an intermediate result of the branch: g n| ... |q<-r<$>a n=([id!id,tail!init]!!mod n 2)q$a n. You don't need a name for the main function. – nimi – 2016-09-22T21:27:58.170

1Oh, you can inline a, too (and switch back to the 1<2 guard): g n| ... |1<2=[id!id,tail!init]!!mod n 2=<<map r$r$(\x->(x<$[1..x])++[x+1..n])<$>[1..n]. – nimi – 2016-09-22T22:01:00.017

1Last one for today: m=map, in !: ...(++).m y and g: g n|n<0=m(m(abs.((n-1)+)))$g$abs n|1<2=[id!id,tail!init]!!mod n 2=<<m r$r$m(\x->(x<$[1..x])++[x+1..n])[1..n]. – nimi – 2016-09-22T22:48:27.550

1

JavaScript (ES6), 107 bytes

(n,l=Math.abs(n+n-n%2))=>[...Array(l--)].map((_,i,a)=>a.map((_,j)=>(j=Math.min(i,l-i,j,l-j),n<0?-n-j:j+1)))

l is the size of the array. The n<0?-n-j:j+1 seems awkward but I can't find anything better.

Neil

Posted 2016-09-22T15:10:03.533

Reputation: 95 035

1

Vim, 152 143 bytes

I'm sure this could be golfed more, especially those last two lines, but my brain is fried.

D:let@z=@-/abs(@-)
a"nywYp:s/\d/x/g<C-v>
YggP:%s/.*/x \0 x<C-v>
:%s/x\+/\=@n-@z/g<C-v>
<Esc>v0"qda<C-r>=@z<0?1:@-*@z
<Esc>@=@-%2?"":"YPJYp"
@=@-*@z-1.(@-*@z>1?"@q":"")

Try it online!

Here it is in xxd format with unprintable characters:

0000000: 443a 6c65 7440 7a3d 402d 2f61 6273 2840  D:let@z=@-/abs(@
0000010: 2d29 0a61 226e 7977 5970 3a73 2f5c 642f  -).a"nywYp:s/\d/
0000020: 782f 6716 0a59 6767 503a 2573 2f2e 2a2f  x/g..YggP:%s/.*/
0000030: 7820 5c30 2078 160a 3a25 732f 785c 2b2f  x \0 x..:%s/x\+/
0000040: 5c3d 406e 2d40 7a2f 6716 0a1b 7630 2271  \=@n-@z/g...v0"q
0000050: 6461 123d 407a 3c30 3f31 3a40 2d2a 407a  da.=@z<0?1:@-*@z
0000060: 0a1b 403d 402d 2532 3f22 223a 2259 504a  ..@=@-%2?"":"YPJ
0000070: 5970 220a 403d 402d 2a40 7a2d 312e 2840  Yp".@=@-*@z-1.(@
0000080: 2d2a 407a 3e31 3f22 4071 223a 2222 29    -*@z>1?"@q":"")

Explanation

It builds the pyramid from the center out, surrounding the center number with xes:

x x x
x 5 x
x x x

Then it replaces the xes with the next number and surrounds it with xes again:

x x x x x
x 4 4 4 x
x 4 5 4 x
x 4 4 4 x
x x x x x

...and so on. For even numbers it does the same thing but starts with a 2x2 base.

Here's the code "ungolfed." It's somewhat unconventional in that I "record" a macro by typing it into a buffer (hence all the <C-v>s) and then deleting it into a register, which is the best way I found to compose a macro without actually executing the keystrokes.

D:let@z=@-/abs(@-)<CR>       " Delete the input (into @-) and set @z to -1 if @- is negative; otherwise 1
a                            " Enter insert mode to compose the macro
  "nyw                         " Copy the number under the cursor to @n
  Yp                           " Copy this line and paste it below
  :s/\d/x/g<C-v><CR>           " Replace digits in the copy with 'x'
  YggP                         " Copy this line and paste it at the top of the buffer
  :%s/.*/x \0 x<C-v><CR>       " Add an 'x' before and after each line
  :%s/x\+/\=@n-@z/g<C-v><CR>   " Replace all 'x'es (and 'xx'es etc.) with the next number
<Esc>v0"qd                   " Done composing macro; delete it into @q (buffer is now empty)
a<C-r>=@z<0?1:@-*@z          " Append the center number (1 or abs(@-)) to the buffer
<Esc>@=@-%2?"":"YPJYp"       " If the input is even, make a 2x2 square
@=@-*@z-1.(@-*@z>1?"@q":"")  " Execute the macro abs(@-)-1 times if it's > 1

Jordan

Posted 2016-09-22T15:10:03.533

Reputation: 5 001

0

PHP, 215 Bytes

for($i=0;$i<$m=($r=($s=abs($n=$argv[1]))*2-$s%2)**2;){$i%$r?:print"\n";$l=min(($x=$i%$r+1)<$s?$x:$x=$r-$x+1,($z=1+floor($i++/$r))<$s?$z:$z=$r-$z+1);$o=($n>0)?$l:$s+1-$l;echo str_pad(" ",1+strlen($s)-strlen($o)).$o;}

Jörg Hülsermann

Posted 2016-09-22T15:10:03.533

Reputation: 13 026

0

R, 112 bytes

k=abs(n);l=2*k;m=diag(l);for(i in 1:k){m[i:(l+1-i),i:(l+1-i)]=i};if(n%%2==1){m=m[-k,-k]};if(n<0){m=abs(m-1+n)};m

Needs integer n in workspace, otherwise run n=scan() for an extra 8 bytes.

k=abs(n)
l=2*k
m=diag(l)                    # Initialize quadratic 2*|n| matrix
for(i in 1:k){
    m[i:(l+1-i),i:(l+1-i)]=i # Assign values to matrix elements according
                             # to their index
}
if(n%%2==1){
   m=m[-k,-k]                # If n is odd, delete middle row and column
}
if(n<0){
    m=abs(m-1+n)             # If n < 0, flip values
}
m                            # Print matrix

Headcrash

Posted 2016-09-22T15:10:03.533

Reputation: 11