Rotate the anti-diagonals

32

2

Background

In most reasonable programming languages, it's very easy to rotate the rows or columns of a 2D array. In this challenge, your task is to rotate the anti-diagonals instead. Recall that the anti-diagonals of a 2D array are its 1D slices taken in the northeast direction ↗.

Input

A non-empty rectangular 2D array of single-digit numbers in any reasonable format. Note that the array may not be a square.

Output

The same array, but with each anti-diagonal rotated one step to the right.

Example

Consider the 3x4 input array

0 1 2 3
4 5 6 7
8 9 0 1

The anti-diagonals of this array are

0
4 1
8 5 2
9 6 3
0 7
1

Their rotated versions are

0
1 4
2 8 5
3 9 6
7 0
1

Thus the correct output is

0 4 5 6
1 8 9 0
2 3 7 1

Rules and scoring

You can write a full program or a function. It's also acceptable to write a function that modifies the input array in place, if your language allows that. The lowest byte count wins, and standard loopholes are disallowed.

Leaderboard

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

To make sure that your answer shows up, please start your answer with a headline, using the following Markdown template:

## Language Name, N bytes

where N is the size of your submission. If you want to include multiple numbers in your header (e.g. because your score is the sum of two files, or you want to list interpreter flag penalties separately, or you want to show old scores that you improved), make sure that the actual score is the last number in the header.

var QUESTION_ID=63755,OVERRIDE_USER=32014;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"http://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

Additional test cases

Input:
4
Output:
4

Input:
5 6 1
Output:
5 6 1

Input:
0 1
6 2
Output:
0 6
1 2

Input:
6 3 0 8
4 6 1 4
6 2 3 3
9 3 0 3
Output:
6 4 6 1
3 6 2 3
0 9 3 0
8 4 3 3

Input:
5 8 2
6 7 3
2 6 1
6 0 6
6 4 1
Output:
5 6 7
8 2 6
2 6 0
3 6 4
1 6 1

Input:
9 9 4 0 6 2
2 3 2 6 4 7
1 5 9 3 1 5
0 2 6 0 4 7
Output:
9 2 3 2 6 4
9 1 5 9 3 1
4 0 2 6 0 4
0 6 2 7 5 7 

Zgarb

Posted 2015-11-13T16:21:36.240

Reputation: 39 083

Answers

20

CJam, 20

{z_)\zLa+(@+\.+s\,/}

Written as a function block. Try it online

Explanation:

The input can be viewed like this:

input diagram

That is, we separate the top row and right column from the rest of the matrix, and consider those elements in the order shown by the arrow.

Then the output is like this:

output diagram

The remaining rectangular block is moved diagonally as a whole, and the edge elements are rearranged in the order/positions showed by the new arrow.

The code does almost exactly that, except the output is first generated with the arrow going straight down (so the matrix has a tail, like the letter P), then corrected.

z      zip (transpose) the matrix
_      make a copy
)      take out the last row (right column before transposing)
\      swap with the rest of the matrix
z      transpose back
La+    append an empty row (needed for the single-column case,
        which leaves an empty matrix here)
(      take out the first row (top row without the corner)
@+     bring the right column to the top of the stack and concatenate
        obtaining an array of the edge elements (marked with the blue arrow)
\      swap with the remaining part (big white block in the diagrams)
.+     concatenate element by element
        each edge element is concatenated with a row of the white block
        after the white block runs out, the remaining elements form new rows
s      convert the whole thing to a string (concatenating all rows)
\      swap with the copy of the transposed matrix
,      get its length (number of original columns)
/      split the string into rows of that length

aditsu quit because SE is EVIL

Posted 2015-11-13T16:21:36.240

Reputation: 22 326

The Pyth answer is also 20 bytes, but yours was earlier, so I'm accepting it. – Zgarb – 2015-12-07T17:24:38.033

9

CJam, 44 43 42 40 bytes

qN/:ReeSf.*:sz1fm<{Rz,{(S-(o\}*~]{},No}h

Test it here.

Hmm, much better than my first attempt, but I have a feeling Dennis will solve this in much less anyway...

Input and output are as ASCII grids:

0123
4567
8901

gives

0456
1890
2371

Martin Ender

Posted 2015-11-13T16:21:36.240

Reputation: 184 808

7Crossed out 44 is still regular 44 ;( – AdmBorkBork – 2015-11-13T16:46:04.523

3@TimmyD I should have waited until the end of the grace period to edit it from 47 right down to 43. :P – Martin Ender – 2015-11-13T16:48:14.763

Yes! It's become a meme.

– intrepidcoder – 2015-11-13T19:21:38.383

1I FINALLY went and learned a golfing language so I could golf 4 bytes to 3 and join the link chain :) – Khuldraeseth na'Barya – 2018-03-03T21:17:28.500

6

J, 24 char

Function taking one argument.

$$<@(1&|.)/./:&;</.@i.@$

J has an operator /. called Oblique. It can't invert it, so reconstruction isn't trivial, but you can consider "listing obliques" as a permutation of the elements of the array. So we invert that permutation with /: (dyadic Sort), by putting the "listing obliques" permutation for that size (</.@i.@$) on the right and our new oblique values, rotated properly, on the left. Then we reshape this list into the old rectangular array using good old $$.

   3 4$i.10
0 1 2 3
4 5 6 7
8 9 0 1
   ($$<@(1&|.)/./:&;</.@i.@$) 3 4$i.10
0 4 5 6
1 8 9 0
2 3 7 1

Try it online.

algorithmshark

Posted 2015-11-13T16:21:36.240

Reputation: 8 144

This is peak J right here. Well done. – Jonah – 2019-04-12T02:17:12.050

5

J, 38 30 bytes

8 bytes saved thanks to @algorithmshark.

{./.((}.~#),~({.~#),.])}:"1@}.   

The function collects the top and left edges into a list, cuts the list to two pieces of sufficient sizes and stitches them to the right and bottom of the core part.

Usage:

   ]input=.0 1 2 3, 4 5 6 7,: 8 9 0 1
0 1 2 3
4 5 6 7
8 9 0 1
   ({./.((}.~#),~({.~#),.])}:"1@}.) input
0 4 5 6
1 8 9 0
2 3 7 1

Try it online here.

randomra

Posted 2015-11-13T16:21:36.240

Reputation: 19 909

1Down to 30 char: {./. replaces }:@{.,{:"1, and you can save two tildes by flipping the train around: {./.((}.~#),~({.~#),.])}:"1@}.. – algorithmshark – 2015-11-13T22:12:55.373

4

Julia, 153 149 139 bytes

A->(length(A)>1&&((m,n)=size(A);r(X)=for i=1:n X[:,i]=reverse(X[:,i])end;r(A);for i=-m:m A[diagind(A,i)]=circshift(diag(A,i),1)end;r(A));A)

This creates an unnamed function that accepts an array and returns the input array modified in place.

Ungolfed:

# Create a function to reverse the columns of a matrix
function revcols!(X)
    for = 1:size(X, 2)
        X[:,i] = reverse(X[:,i])
    end
    return X
end

# Our main function
function zgarb!(A)
    # Only perform operations if the array isn't one element
    if length(A) > 1
        # Record the number of rows
        m = size(A, 1)

        # Reverse the columns in place
        revcols!(A)

        # Shift each diagonal
        for i = -m:m
            A[diagind(A, i)] = circshift(diag(A, i), 1)
        end

        # Reverse the columns back
        revcols!(A)
    end
    return A
end

Thanks to Martin Büttner for algorithmic advice and for saving 4 bytes!

Alex A.

Posted 2015-11-13T16:21:36.240

Reputation: 23 761

3

Pyth, 20 bytes

J+PhQ.)MQ++L.(J0tQ]J

Uses Adistu's approach of removing the top row and right column, then sticking them on the left and bottom. But with mutable data structures, not transpositions.

isaacg

Posted 2015-11-13T16:21:36.240

Reputation: 39 268

3

ES6, 75 bytes

This accepts an array of arrays as a parameter and modifies it in place.

a=>{t=a.shift();a.map(r=>{t.push(r.pop());r.unshift(t.shift())});a.push(t)}

Ungolfed:

function anti_diagonal(array) {
    var temp = array.shift(); // strip off the first row
    array.forEach(row => temp.push(row.pop())); // strip off the last elements of each row
    array.forEach(row => row.unshift(temp.shift())); // distribute the elements to the beginning of each row
    array.push(temp); // the remaining elements become the last row
}

See @aditsu's diagram for further clarification.

Neil

Posted 2015-11-13T16:21:36.240

Reputation: 95 035

You could save 2 bytes by changing {t.push(r.pop());r.unshift(t.shift())} to t.push(r.pop())+r.unshift(t.shift()) – user81655 – 2015-11-14T09:42:03.353

2

Octave, 85 bytes

@(a)[(b=[a(1,1:end),a(2:end,end)'])(1:(s=size(a)(1)))',[a(2:end,1:end-1);b(s+1:end)]]

I hope I could get rid of the ends.

alephalpha

Posted 2015-11-13T16:21:36.240

Reputation: 23 988

1

Python 2, 113 104 94 bytes

f=lambda i,b=[]:i and[b and b[:1]+i[0][:-1]]+f(i[1:],b[1:]or i[0][:-1]+[l[-1]for l in i])or[b]

Try it online!

This is a fairly literal interpretation of @aditsu's method. Python's syntax for treating empty lists as False helped save an extra 10 bytes.

SmileAndNod

Posted 2015-11-13T16:21:36.240

Reputation: 119

saved 8 bytes by discarding rows as I go – SmileAndNod – 2019-04-12T05:50:51.657

More test cases – SmileAndNod – 2019-04-12T06:00:11.467

1You probably don't need the 0 in [0:1] – Jo King – 2019-04-12T06:30:25.193