Rotate matrix rows according to the row above

7

Specifications

For this challenge, you will be given a matrix of some sort in any reasonable format for a 2-D array. For each row except the last, in order from top (first) to bottom (last), rotate the row below it by x to either direction (you choose a consistent direction to use) where x is the first element in the current row.

Reference

A reference implementation in Python can be found here

Example

Let's walk through an example. Take the following matrix for example:

1 5 8
4 7 2
3 9 6

Let's say we're rotating right. First we rotate [4 7 2] to the right by 1 because the first element of [1 5 8] is 1. Thus, we get [2 4 7] as the second row. The matrix is now like this:

1 5 8
2 4 7
3 9 6

Then, we rotate [3 9 6] to the right by 2 because the first element of the second row is 2. Thus we get:

1 5 8
2 4 7
9 6 3

Challenge

Implement the above

Test Cases

Test cases are given as a list of lists in Python style.

Input -> Output
[[6, 7, 10, 1, 10, 7], [7, 3, 7, 8, 9, 2], [6, 8, 3, 9, 3, 1], [6, 3, 8, 6, 4, 1], [7, 5, 2, 9, 7, 2], [2, 10, 9, 9, 7, 9], [8, 8, 10, 10, 8, 4]] -> [[6, 7, 10, 1, 10, 7], [7, 3, 7, 8, 9, 2], [1, 6, 8, 3, 9, 3], [1, 6, 3, 8, 6, 4], [2, 7, 5, 2, 9, 7], [7, 9, 2, 10, 9, 9], [4, 8, 8, 10, 10, 8]]
[[8, 10, 4, 3, 9, 4, 6], [8, 8, 8, 8, 6, 7, 5], [6, 2, 2, 4, 8, 9, 6], [1, 7, 9, 9, 10, 7, 8]] -> [[8, 10, 4, 3, 9, 4, 6], [5, 8, 8, 8, 8, 6, 7], [2, 4, 8, 9, 6, 6, 2], [7, 8, 1, 7, 9, 9, 10]]
[[6, 2, 4, 4, 4], [5, 9, 10, 5, 4], [3, 5, 7, 2, 2], [1, 5, 5, 10, 10], [8, 2, 3, 2, 1], [3, 3, 9, 5, 10], [9, 5, 9, 7, 2]] -> [[6, 2, 4, 4, 4], [4, 5, 9, 10, 5], [5, 7, 2, 2, 3], [1, 5, 5, 10, 10], [1, 8, 2, 3, 2], [10, 3, 3, 9, 5], [9, 5, 9, 7, 2]]
[[3, 6, 3, 7, 4], [8, 8, 1, 5, 8], [7, 5, 1, 9, 4], [3, 9, 10, 8, 6]] -> [[3, 6, 3, 7, 4], [1, 5, 8, 8, 8], [4, 7, 5, 1, 9], [9, 10, 8, 6, 3]]
[[5, 6, 1, 2, 6], [1, 10, 10, 1, 4], [6, 2, 7, 1, 7], [9, 5, 8, 6, 3], [4, 5, 1, 2, 1], [8, 6, 1, 1, 3]] -> [[5, 6, 1, 2, 6], [1, 10, 10, 1, 4], [7, 6, 2, 7, 1], [6, 3, 9, 5, 8], [1, 4, 5, 1, 2], [3, 8, 6, 1, 1]]
[[10, 1, 2], [9, 9, 10], [2, 4, 7]] -> [[10, 1, 2], [10, 9, 9], [7, 2, 4]]
[[4, 5, 6], [6, 9, 4], [9, 3, 2], [3, 5, 9], [5, 5, 3], [9, 1, 4]] -> [[4, 5, 6], [4, 6, 9], [2, 9, 3], [5, 9, 3], [5, 3, 5], [1, 4, 9]]
[[8, 7, 6, 5], [9, 8, 6, 6], [7, 9, 7, 10]] -> [[8, 7, 6, 5], [9, 8, 6, 6], [10, 7, 9, 7]]
[[10, 2, 8, 8, 1], [2, 10, 1, 4, 10], [3, 2, 5, 3, 8], [5, 1, 8, 1, 8], [6, 1, 3, 1, 2], [7, 9, 1, 1, 2]] -> [[10, 2, 8, 8, 1], [2, 10, 1, 4, 10], [3, 8, 3, 2, 5], [8, 1, 8, 5, 1], [3, 1, 2, 6, 1], [1, 1, 2, 7, 9]]
[[9, 1, 3, 2, 7], [3, 8, 10, 3, 3], [8, 10, 7, 9, 5], [8, 1, 4, 9, 9], [6, 8, 4, 10, 10], [4, 7, 6, 2, 2], [8, 5, 3, 7, 6]] -> [[9, 1, 3, 2, 7], [8, 10, 3, 3, 3], [7, 9, 5, 8, 10], [9, 9, 8, 1, 4], [8, 4, 10, 10, 6], [6, 2, 2, 4, 7], [6, 8, 5, 3, 7]]

Generate more testcases here

HyperNeutrino

Posted 2017-09-07T21:52:10.093

Reputation: 26 575

1we rotate [4 7 2] to the right by 1 ... we get [2 7 4] Wait, what? Shouldn't it be [2 4 7]? Or am I misunderstanding "rotation"? – totallyhuman – 2017-09-07T21:58:38.840

1For each row except the last Shouldn't that be except the first? – totallyhuman – 2017-09-07T22:00:54.003

@icrieverytim rotate the row below it technically this is inconsistent with my title but eh – HyperNeutrino – 2017-09-07T22:03:55.420

@icrieverytim no you're right, i'm just being dumb whoops. prolly should've used my program – HyperNeutrino – 2017-09-07T22:04:11.140

2Are we guaranteed that the matrix is positive integers and that the matrix has at least two rows? – Giuseppe – 2017-09-07T22:14:18.023

Exactly what I was about to ask, @Giuseppe. – Shaggy – 2017-09-07T22:18:06.850

1Since x can be larger than the length of the row below (according to the test cases), what exactly is [2, 5, 8] rotated by 4? The second test case says it's [2, 5, 8] which doesn't make a lot of sense to me... – totallyhuman – 2017-09-07T22:20:49.200

The reference implementation is broken, the rotate method currently concatenates two slices to yield the same as array whatever the amount is. I think this fixes it.

– Jonathan Allan – 2017-09-07T22:43:36.037

@JonathanAllan Yup that seems to fix it, thanks – HyperNeutrino – 2017-09-07T22:53:29.990

@Giuseppe Yup, you can – HyperNeutrino – 2017-09-07T22:53:45.647

@Shaggy ^^^^^^^ – HyperNeutrino – 2017-09-07T22:53:52.030

@icrieverytim I'll fix that; I need to do % which I forgot – HyperNeutrino – 2017-09-07T22:54:04.127

Answers

5

Husk, 4 bytes

G(ṙ←

Try it online!

Rotates rows to the left.

Explanation

G in Husk is scanl (or cumulative reduce from left, as some languages call it). When given a function of type x->x->x (like in this case) it can use as starting value the first element of the list.

( is needed here to combine the following two functions into a single one.

is "rotate to the left" and takes a number and a list as arguments.

returns the first element of a list.

Leo

Posted 2017-09-07T21:52:10.093

Reputation: 8 482

3

Jelly, 6 5 bytes

ṙ@Ḣð\

Try it online!

Rotates to the left.

Saved a byte thanks to @Jonathan Allan.

Explanation

ṙ@Ḣð\  Input: array of arrays M
   ð\  Cumulative reduce over each array using
ṙ@       Rotate the RHS array using each in the LHS array
  Ḣ      Head

miles

Posted 2017-09-07T21:52:10.093

Reputation: 15 654

You can dump the – Jonathan Allan – 2017-09-07T22:48:39.213

@JonathanAllan Thanks. Isn't ɓ supposed to work here, as in ṙḢɓ\. – miles – 2017-09-07T22:52:47.107

Ah, that actually may require a code change to reduce_cumulative; it would make sense to do so... – Jonathan Allan – 2017-09-07T23:00:20.360

3

C++, 187 149 bytes

  • 38 bytes thanks to Karl Napf

Output is done by the reference type parameter The parameter's type have to be a std::vector<std::vector<int>> type

auto r=[](auto&a){for(int i=1,j,v;i<a.size();++i){v=a[i-1][0]%a[i].size();for(j=0;j<v;++j){a[i].insert(a[i].begin(),a[i].back());a[i].pop_back();}}};

Trying to do as #define A a[i] and replacing all occurences of a[i] by A will result with same byte count code

Code to help for the test :

//Shift operator overload
std::ostream& operator<<(std::ostream& os, std::vector<std::vector<int>>& v) {
    os << "{\n";
    for (auto&a : v) {
        os << "\t{ ";
        for (auto&b : a) {
            os << b << ' ';
        }
        os << "},\n";
    }
    return os << "}\n";
}

And in the main function

std::vector<std::vector<int>> t{
    {1,5,8},
    {4,7,2},
    {3,9,6}
};

std::cout << t;

r(t);

std::cout << t;

HatsuPointerKun

Posted 2017-09-07T21:52:10.093

Reputation: 1 891

1

You can drop the #include and std::vector<... declarations by using an unnamed generic lambda [](auto&a){...} and demanding the input to be like vector<vector<int>> as I did in my challenges, e.g. https://codegolf.stackexchange.com/questions/100205/do-matrix-multiplication/100241#100241

– Karl Napf – 2017-09-08T16:08:26.003

2

Haskell, 84 59 45 bytes

Shifts to the left (now using Leo's approach):

scanl1(\a r->(drop<>take$a!!0`mod`length r)r)

Try it online!

ბიმო

Posted 2017-09-07T21:52:10.093

Reputation: 15 345

59 bytes: Try it online!

– Laikoni – 2018-05-04T23:36:12.703

@Laikoni: Damn that's so much nicer and saves a whole lot of bytes, thanks a lot! – ბიმო – 2018-05-05T00:23:03.340

1

Python 2, 65 bytes

l=input();K=0
for i in l:g=-K%len(i);e=i[g:]+i[:g];print e;K=e[0]

Try it online!

Python 2, 55 bytes (possibly broken)

If this version is found to fail for some test cases, I can assure you the above works. I am currently half-asleep, so feel free to remove this version in case it is invalid by editing.

l=input();K=0
for i in l:e=i[-K:]+i[:-K];print e;K=e[0]

Try it online!

Mr. Xcoder

Posted 2017-09-07T21:52:10.093

Reputation: 39 774

You need to add modulo somewhere in there. The rotation numbers are sometimes longer than the lengths. – totallyhuman – 2017-09-07T22:15:26.333

@icrieverytim I think it's fixed – Mr. Xcoder – 2017-09-07T22:17:32.680

...Actually, the test cases don't reflect that, which is in turn because the reference implementation doesn't use modulo. I'll ask OP whether it's needed. – totallyhuman – 2017-09-07T22:19:11.517

1

05AB1E, 9 bytes

vyNFÁ}=нƒ

Try it online!

vy        # For each row:
  NFÁ}    #   Rotate this row N times (initially 0)
      =   #   Print without popping
       н  #   Get the head
        ƒ #   Assign that to N 

Riley

Posted 2017-09-07T21:52:10.093

Reputation: 11 345

0

Perl 5, 41 + 1 (-a) = 42 bytes

push@F,shift@F for 1..$r;say"@F";$r=$F[0]

Try it online!

Rotates to the left. Takes the input as lines of space separated integers.

How?

Remove an element from the left end of the list, put it on the right end as many times as we should rotate ($r). Since $r starts at undef (equivaltent to 0 in this usage), nothing happens to the first line. Output the list. Save the first element of the list in $r so we can rotate that many times on the next line.

Xcali

Posted 2017-09-07T21:52:10.093

Reputation: 7 671

0

Pyth, 11 bytes

VQ=ZhJ.>NZJ

Try it here!

Explanation

  • VQ - For each list in the matrix input:

    • =Z - Assign Z to the value of the below statement. Its initial value is 0, so that helps us with the first row.

    • h - The first element of ...

    • J.>NZ - ... The current list, cyclically rotated by Z places, and assigned to a variable J.

    • J - Print J.

Mr. Xcoder

Posted 2017-09-07T21:52:10.093

Reputation: 39 774

0

R, 77 bytes

function(B){for(i in 2:nrow(B))B[i,]=rep(B[i,],sum(B))[1:ncol(B)+B[i-1,1]]
B}

Try it online!

Rotates rows to the right.

Replicates each row of B sum(B) times (creating a huge vector), then grabs the appropriate values from that replicated vector to put into the correct row.

I also wrote a function in the header that converts from the python matrix format to R matrices.

Giuseppe

Posted 2017-09-07T21:52:10.093

Reputation: 21 077

0

APL (Dyalog), 14 bytes

Anonymous tacit prefix function. Takes list of lists as argument and prints rows on separate lines with the numbers in each row separated by single spaces. Rotates left (although the explanation mentions how rotate right).

{⎕←⍺⌽⍨⊃⍵}/0,⍨⌽

Try it online!

 reverse the argument (because reduction is right-to-left)

0,⍨ append a zero (for initial rotation of zero steps)

{}/ reduce by the following anonymous lambda, where is the element on the left and on the right (the reduction goes right-to-left

 pick the first of the right argument

⍺⌽⍨ rotate the left argument to the left* that many steps

⎕← output to STDOUT with a trailing line-break


* To rotate right, insert a - to the right of . This will negate the rotation amount.

Adám

Posted 2017-09-07T21:52:10.093

Reputation: 37 779