How does the TED Talk home page organise the grid of videos? - algorithm

I've been trying to work out exactly how the TED Talk homepage works. Leaving aside all the animation rubbish, I find the way that the boxes are organised is really fascinating.
At first glance it looks like the jQuery masonry plugin, bu it quickly becomes clear that it tends to create several right angle triangle shapes, but has no fixed number of columns or rows, and the final shape produced is always completely solid (no hollow parts).
My initial assumption was that the boxes (their size is predetermined by some factor on the site) were sorted randomly and then sequentially added to the grid using a few simple rules, however I can't identify what those rules might be, or how they could prevent any hollows in the final shape.
Does anyone have any idea how this works?

Could be wrong but a few observations:
Each section has 19 videos
There are 4 sizes 1 (#1), 1/4 (#2), 1/16 (#3) and 1/32 (#4)
For a given section, there are always 4(#1). The number of (#2), (#3) and (#4) can be either:
4(#1), 10(#2), 4(#3), 1(#1) = 19
4(#1), 11(#2), 4(#3), 0(#1) = 19
4(#1), 11(#2), 3(#3), 1(#1) = 19
4(#1), 12(#2), 2(#3), 1(#1) = 19
4(#1), 13(#2), 1(#3), 1(#1) = 19
As for the order:
The first row always contains 2(#1) and 4(#2)
(#4) are always at the bottom of a column

Here is the javascript code which does it (you need a html page with a div#container):
function ted_layout(settings, coordinates_array, num_elements, start_x, start_y, arrangement, remaining_elements, is_child){
var num_columns = arrangement.length;
var col = 0;
var current_x = start_x;
while( col < num_columns){
var column_x_scale = 100 / arrangement[col];
var current_column_arrangement;
if(is_child){
if(num_elements > 14){
if(column_x_scale == 50){
current_column_arrangement = random_shuffle([1, 2, 2]);
} else {
current_column_arrangement = random_shuffle([1, 2]);
}
} else if(num_elements > 10){
if(column_x_scale == 50){
current_column_arrangement = [1];
} else {
current_column_arrangement = random_shuffle([1, 2]);
}
} else{
current_column_arrangement = random_shuffle([1, 2]);
}
} else {
if(num_elements > 14){
if(column_x_scale == 25){
current_column_arrangement = [1, 1];
} else {
current_column_arrangement = [1];
}
} else if(column_x_scale == 25){
current_column_arrangement = [1, 1];
} else {
current_column_arrangement = [1];
}
}
var num_rows = current_column_arrangement.length;
var current_y = start_y;
var row = 0;
while(row < num_rows){
var numRects = current_column_arrangement[row];
var current_rectangle = 0;
var current_rectangle_x = current_x;
while( current_rectangle < numRects){
if(remaining_elements == 0){
return coordinates_array;
}
var currScale = column_x_scale/numRects;
var height = settings.height * currScale*0.01;
var width = settings.width * currScale*0.01;
if(current_rectangle == numRects-1 && row == num_rows-1 && is_child && Math.random() > 0.5){
coordinates_array.push({x: current_rectangle_x, y:current_y, w:width/2, h:height/2, scale:currScale/2*0.01*2})
}
else{
coordinates_array.push({x: current_rectangle_x, y:current_y, w:width, h:height, scale:currScale*0.01*2})
}
current_rectangle_x += width;
remaining_elements--;
current_rectangle++;
}
row++;
current_y += height;
}
current_x = current_rectangle_x;
col++;
}
if( remaining_elements > 0){
coordinates_array = ted_layout(settings, coordinates_array, num_elements, start_x, current_y, random_shuffle([2, 4, 4, 2]), remaining_elements, true);
}
return coordinates_array;
}
function generate_ted_layout(num_elements){
var settings = {
width: 640,
height: 480,
};
var coordinates_array=[];
returned = ted_layout(settings, coordinates_array, num_elements, 0, 0, random_shuffle([2, 4, 4, 2]), num_elements, false);
console.log("Returned", returned)
return returned;
}
function random_shuffle(array){
var temp;
for(var i = array.length - 1; i >= 1; i--){
var elem = Math.floor(Math.random() * (i + 1));
temp = array[elem];
array[elem] = array[i];
array[i] = temp;
}
return array;
}
function initAndLayout() {
var items = generate_ted_layout(20);
var container = $('#container'); // cache jquery object
console.log(items);
for (var i = 0; i < items.length; i++)
{
var item = items[i];
console.log(item);
$('#container').append($('<div class="item"></div>').css({'left': item.x, 'top': item.y, 'width': item.w, 'height': item.h}));
}
}

I think I've worked it out.
First of all the number of items varies substantially, I'm currently viewing a page with only 13 boxes.
To start I'll name each of the 4 sizes of blocks from largest to smallest as:
A,B,C,D
As we know the first 'row' contains two As and two vertical stacks of Bs, for example:
_______________________
| A | B | A | B |
| |___| |___|
| | B | | B |
|_______|___|_______|___|
The arrangement of these appears to be random, but the Bs are always in the same vertical pattern. Looking at this just now I realised that there are only two rows, and the second row works in the same way.
The second row is twice the height of the first, taking up the rest of the page. It is built of horizontally stacked patterns of shapes, which are (at least in part) selected randomly.
I've found 9 of these patterns of shapes, two of which are a single A or B and the rest are:
_______ _______ _______ ___ ___ _______ ___
| B | B | | A | | B | B | |C|C| | B | | A | |C|C|
|___|___| | | |___|___| | B | |___| | |
| A | | | | B | B | |___| |C|D | |
| | |_______| |___|___| |_______|
| | | B | B | | A | | B |
|_______| |___|___| | | |___|
|B |C| |B |C| | |
|___| |___| |_______|
The next question is how are these selected? There may be some clever searching to find the best configuration: for example if there are X items to be displayed we need to find a configuration with a total of X which does not exceed the width of the row.
This could be done with a metric of pattern density, which would be number of blocks divided by the width of the pattern.

Related

the data method of vector has some wrong

I use the data method of vector in C++, but I have some problems, the code is in belows:
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> myvector (5);
int* p = myvector.data();
*p = 10;
++p;
*p = 20;
p[2] = 100;
std::cout << "myvector contains:";
for (unsigned i=0; i<myvector.size(); ++i)
std::cout << ' ' << myvector[i];
std::cout << '\n';
return 0;
}
the result is myvector contains: 10 20 0 100 0, but why the result is not myvector contains: 10 20 100 0 0, the first one *p = 10; is 10, the second one ++p;*p = 20; is 20, that's all right, but the third one p[2] = 100; should be 100, but it is 0, why?
With visuals:
std::vector<int> myvector (5);
// ---------------------
// | 0 | 0 | 0 | 0 | 0 |
// ---------------------
int* p = myvector.data();
// ---------------------
// | 0 | 0 | 0 | 0 | 0 |
// ---------------------
// ^
// p
*p = 10;
// ----------------------
// | 10 | 0 | 0 | 0 | 0 |
// ----------------------
// ^
// p
++p;
// ----------------------
// | 10 | 0 | 0 | 0 | 0 |
// ----------------------
// ^
// p
*p = 20;
// ----------------------
// | 10 | 20 | 0 | 0 | 0 |
// ----------------------
// ^
// p
p[2] = 100;
// -------------------------
// | 10 | 20 | 0 | 100 | 0 |
// -------------------------
// ^ ^
// p p[2]
It's helpful to remember that p[2] is a shorter way to say *(p + 2).
Because you are modifying p itself.
After ++p (which I remember you it's equivalent to p = p + 1), p points to the element at index 1, so p[2] points at element at index 3 from the beginning of the vector which is why the fourth element is changed instead.
After ++p, pointer p is pointing to myvector[1].
Then we have:
p[0] pointing to myvector[1]
p[1] pointing to myvector[2]
p[2] pointing to myvector[3]

how to detect intersecting and overlapping bounding box in a lot of bounding box?

I generate a lot of bounding box in an image. How can I merge the overlapping bounding box in an image?
For example,
_________________ ________________________
| | | |
| —————————|———— | |
| | | | | |
———————|—————————— | ——> | |
| | | |
| ————————|—————— | |
—————|———————— | | |
| | | |
| | | |
———————————————— ________________________
I know use the rectangle 1 | rectangle 2 to generate a new rectangle.
It can detected and merged them in the approach as follow.(From Efficient way to combine intersecting bounding rectangles)
if((rect1 & rect2) == rect1) ... // rect1 is completely inside rect2; do nothing.
else if((rect1 & rect2).area() > 0) // they intersect; merge them.
newrect = rect1 | rect2;
... // remove rect1 and rect2 from list and insert newrect.
But I mean how to judge which rectangle are overlapped when three or four rectangles overlapped. I though I could use the overlapping area to judge whether they are overlapped.
Is that anything else efficient approach?
thank you so much.
Here's a some quick pseudocode
Generate binary maps for each rectangle which are the size of the image.
Add these binary maps to create a new single merged map. (You might have to threshold them back down to 1's and 0's)
Generate a new bounding box for this using your original algorithm (the one you used to get the first 3 bounding boxes)
This function take the contours of the image and return the merged boxes you want:
ae::error_code authenticator::get_boxes(const std::vector<std::vector<cv::Point>>& contours, std::vector<cv::Rect>& boxes){
std::vector<cv::Rect> bounding_boxes;
for (const auto& contour_item : contours){
bounding_boxes.push_back(cv::boundingRect(contour_item));
}
auto rect_corners = [](const cv::Rect& rect)->std::vector<cv::Point>{
return{ cv::Point(rect.x, rect.y),
cv::Point(rect.x + rect.width, rect.y),
cv::Point(rect.x + rect.width, rect.y + rect.height),
cv::Point(rect.x, rect.y + rect.height) };
};
auto check_shared_rects = [](const cv::Rect& rect_a, const cv::Rect& rect_b)->bool{
return (rect_a & rect_b).area() > 0;
};
for (size_t rect_idx = 0; rect_idx < bounding_boxes.size() - 1; ++rect_idx){
for (size_t other_rect_idx = rect_idx + 1; other_rect_idx < bounding_boxes.size(); ++other_rect_idx){
if (check_shared_rects(bounding_boxes[rect_idx], bounding_boxes[other_rect_idx])){
auto new_rect_points(rect_corners(bounding_boxes[rect_idx]));
auto temp_points(rect_corners(bounding_boxes[other_rect_idx]));
new_rect_points.insert(std::end(new_rect_points), std::begin(temp_points), std::end(temp_points));
bounding_boxes.push_back(cv::boundingRect(new_rect_points));
bounding_boxes.erase(std::begin(bounding_boxes) + other_rect_idx);
bounding_boxes.erase(std::begin(bounding_boxes) + rect_idx);
rect_idx = 0;
other_rect_idx = rect_idx;
}
}
}
boxes = bounding_boxes;
return ae::error_code::ae_error_free;
}
EDIT :
You can dismiss the first part about generating the bounding boxes since you have them already.
Sort your bounding boxes by area : the biggest boxes are the one more likely to overlap.
Failing that, you can do a "not so efficient" drawing all the rectangles by doing a union of all rectangles.
You might want to label your overlapping boxes image to select only the overlapping ones and discard the rest.
There might be some trick to use under this idea by using a sort of z-buffer to store which rectangles are drawn on each pixel ?
This is the code i have used for my problem you can use for yours too Enjoy:
function varargout = isBoxMerg(ReferenceBox,TestBox,isNewBox)
X = ReferenceBox; Y = TestBox;
X1 = X(1);Y1 = X(2);W1 = X(3);H1 = X(4);
X2 = Y(1);Y2 = Y(2);W2 = Y(3);H2 = Y(4);
if ((X1+W1)>=X2 && (Y2+H2)>=Y1 && (Y1+H1)>=Y2 && (X1+W1)>=X2 && (X2+W2)>=X1)
Intersection = true;
else
Intersection = false;
end
if (~isNewBox)
varargout{1} = Intersection;
elseif(isNewBox && Intersection)
varargout{1} = Intersection;
a = X1;b=X1+W1;c=Y1;d=Y1+H1;
p = X2;q=X2+W2;r=Y2;s=Y2+H2;
if a<p
newA = a;
else
newA = p;
end
if b>q
newB = b;
else
newB = q;
end
if c<r
newC = c;
else
newC = r;
end
if d>s
newD = d;
else
newD = s;
end
newCC = [newA,newC,abs(newA-newB),abs(newC-newD)];
varargout{2} = newCC;
end

Grouping with Knedo datasource / grid

How do I accomplish this in Kendo Grid/Datasource?
I have data that looks something like this:
Month | Value
--------------
1 | 10
1 | 15
1 | 30
2 | 5
2 | 7
3 | 4
I would like to group that data by month and output it to a grid in this form:
Month | Sum(Value)
------------------
1 | 55
2 | 12
3 | 4
I don't want any group headers and collapsable groups with items on it, I just want that simple output.
How can I do that in Kendo?
I don't think out of the box kendo could get you what you are wanting. You could manually massage the data into the structure you want, and then bind that to a kendo grid.
Take your array of data, group by month, then sum up the value(s);
var g = {};
var data = myData; // Or however you get your data
for(var i = 0; i < data.length; i++) {
var obj = data[i];
if(g[obj.month] === undefined) {
g[obj.month] = obj.value;
}
else {
g[obj.month] += obj.value;
}
}
var results = [];
for(var j in g) {
if(g.hasOwnProperty(j)) {
results.push({ month: j, value: g[j]});
}
}
See sample http://jsbin.com/pipinodoca/1/edit?js,output

Textured triangle strips - rows beyond first row gives garbled output

I'm drawing some "simple" 2D graphics using OpenGL ES, glDrawArrays and GL_TRIANGLE_STRIP.
I'm writing a function whose purpose is to take one 13x13 point (or other arbitrarily sized) texture and output it in specified number of columns and rows. So for 2 rows and 3 columns that would mean an area covered with 6 tiles over 26x39 points. The first row works well with the below code but as soon as I specify 2 or more rows there's just garbled output.
for (int row = 0; row < heightInTiles; row++) {
for (int col = 0; col < widthInTiles; col++) {
vertexIndexOffset += 8;
startX = (GLshort)(col * TEXTUREWIDTH);
startY = (GLshort)(row * TEXTUREHEIGHT);
// Vertices
vertices[vertexIndexOffset] = startX; // 1
vertices[vertexIndexOffset + 1] = startY; //0.0;
vertices[vertexIndexOffset + 2] = startX; // 2
vertices[vertexIndexOffset + 3] = startY + (GLshort)TEXTUREHEIGHT;
vertices[vertexIndexOffset + 4] = (GLshort)(startX + TEXTUREWIDTH); // 3
vertices[vertexIndexOffset + 5] = startY;
vertices[vertexIndexOffset + 6] = (GLshort)(startX + TEXTUREWIDTH); // 4
vertices[vertexIndexOffset + 7] = startY + (GLshort)TEXTUREHEIGHT;
// Texture coords
uvs[vertexIndexOffset] = WRESULT; // 1
uvs[vertexIndexOffset + 1] = 0;
uvs[vertexIndexOffset + 2] = WRESULT; // 2
uvs[vertexIndexOffset + 3] = HRESULTNEXT;
uvs[vertexIndexOffset + 4] = WRESULTNEXT; // 3
uvs[vertexIndexOffset + 5] = 0;
uvs[vertexIndexOffset + 6] = WRESULTNEXT; // 4
uvs[vertexIndexOffset + 7] = HRESULTNEXT;
}
}
Assuming heightInTiles=1 and widthInTiles=2, the code first generates two "stripped" triangles 1234; for the next cell, vertices 5678 are generated, where 3=5 and 4=6. So there are two degenerate triangles (having area 0). However, this works (well, after moving vertexIndexOffset += 8; to the end of the inner loop)
2----------4/6----------8
| | |
| | |
| | |
| | |
1----------3/5----------7
Assuming heightInTiles=2 and widthInTiles=1, the picture looks somewhat different:
6-----------8
| |
| |
| |
| |
2/5--------4/7
| |
| |
| |
| |
1-----------3
Now, what happens if the strip 12345678 is drawn? 123, 234 is OK, but then 345? This overlaps, and note the texture coords for these vertices -- vertices 2 and 5 have different UVs! As above, there are two unwanted triangles, but this time, these don't have area 0 anymore.
When a new row is started, you need to insert two dummy vertices, essentially restarting the strip elsewhere. What if the triangle strip contained 1234455678? Now, 123 and 234 are drawn OK, then 344, 445, 455, and 556 have area 0, the next drawn triangles are 567 and 678.

How do you rotate a two dimensional array?

Inspired by Raymond Chen's post, say you have a 4x4 two dimensional array, write a function that rotates it 90 degrees. Raymond links to a solution in pseudo code, but I'd like to see some real world stuff.
[1][2][3][4]
[5][6][7][8]
[9][0][1][2]
[3][4][5][6]
Becomes:
[3][9][5][1]
[4][0][6][2]
[5][1][7][3]
[6][2][8][4]
Update: Nick's answer is the most straightforward, but is there a way to do it better than n^2? What if the matrix was 10000x10000?
O(n^2) time and O(1) space algorithm ( without any workarounds and hanky-panky stuff! )
Rotate by +90:
Transpose
Reverse each row
Rotate by -90:
Method 1 :
Transpose
Reverse each column
Method 2 :
Reverse each row
Transpose
Rotate by +180:
Method 1: Rotate by +90 twice
Method 2: Reverse each row and then reverse each column (Transpose)
Rotate by -180:
Method 1: Rotate by -90 twice
Method 2: Reverse each column and then reverse each row
Method 3: Rotate by +180 as they are same
I’d like to add a little more detail. In this answer, key concepts are repeated, the pace is slow and intentionally repetitive. The solution provided here is not the most syntactically compact, it is however, intended for those who wish to learn what matrix rotation is and the resulting implementation.
Firstly, what is a matrix? For the purposes of this answer, a matrix is just a grid where the width and height are the same. Note, the width and height of a matrix can be different, but for simplicity, this tutorial considers only matrices with equal width and height (square matrices). And yes, matrices is the plural of matrix.
Example matrices are: 2×2, 3×3 or 5×5. Or, more generally, N×N. A 2×2 matrix will have 4 squares because 2×2=4. A 5×5 matrix will have 25 squares because 5×5=25. Each square is called an element or entry. We’ll represent each element with a period (.) in the diagrams below:
2×2 matrix
. .
. .
3×3 matrix
. . .
. . .
. . .
4×4 matrix
. . . .
. . . .
. . . .
. . . .
So, what does it mean to rotate a matrix? Let’s take a 2×2 matrix and put some numbers in each element so the rotation can be observed:
0 1
2 3
Rotating this by 90 degrees gives us:
2 0
3 1
We literally turned the whole matrix once to the right just like turning the steering wheel of a car. It may help to think of “tipping” the matrix onto its right side. We want to write a function, in Python, that takes a matrix and rotates it once to the right. The function signature will be:
def rotate(matrix):
# Algorithm goes here.
The matrix will be defined using a two-dimensional array:
matrix = [
[0,1],
[2,3]
]
Therefore the first index position accesses the row. The second index position accesses the column:
matrix[row][column]
We’ll define a utility function to print a matrix.
def print_matrix(matrix):
for row in matrix:
print row
One method of rotating a matrix is to do it a layer at a time. But what is a layer? Think of an onion. Just like the layers of an onion, as each layer is removed, we move towards the center. Other analogies is a Matryoshka doll or a game of pass-the-parcel.
The width and height of a matrix dictate the number of layers in that matrix. Let’s use different symbols for each layer:
A 2×2 matrix has 1 layer
. .
. .
A 3×3 matrix has 2 layers
. . .
. x .
. . .
A 4×4 matrix has 2 layers
. . . .
. x x .
. x x .
. . . .
A 5×5 matrix has 3 layers
. . . . .
. x x x .
. x O x .
. x x x .
. . . . .
A 6×6 matrix has 3 layers
. . . . . .
. x x x x .
. x O O x .
. x O O x .
. x x x x .
. . . . . .
A 7×7 matrix has 4 layers
. . . . . . .
. x x x x x .
. x O O O x .
. x O - O x .
. x O O O x .
. x x x x x .
. . . . . . .
You may notice that incrementing the width and height of a matrix by one, does not always increase the number of layers. Taking the above matrices and tabulating the layers and dimensions, we see the number of layers increases once for every two increments of width and height:
+-----+--------+
| N×N | Layers |
+-----+--------+
| 1×1 | 1 |
| 2×2 | 1 |
| 3×3 | 2 |
| 4×4 | 2 |
| 5×5 | 3 |
| 6×6 | 3 |
| 7×7 | 4 |
+-----+--------+
However, not all layers need rotating. A 1×1 matrix is the same before and after rotation. The central 1×1 layer is always the same before and after rotation no matter how large the overall matrix:
+-----+--------+------------------+
| N×N | Layers | Rotatable Layers |
+-----+--------+------------------+
| 1×1 | 1 | 0 |
| 2×2 | 1 | 1 |
| 3×3 | 2 | 1 |
| 4×4 | 2 | 2 |
| 5×5 | 3 | 2 |
| 6×6 | 3 | 3 |
| 7×7 | 4 | 3 |
+-----+--------+------------------+
Given N×N matrix, how can we programmatically determine the number of layers we need to rotate? If we divide the width or height by two and ignore the remainder we get the following results.
+-----+--------+------------------+---------+
| N×N | Layers | Rotatable Layers | N/2 |
+-----+--------+------------------+---------+
| 1×1 | 1 | 0 | 1/2 = 0 |
| 2×2 | 1 | 1 | 2/2 = 1 |
| 3×3 | 2 | 1 | 3/2 = 1 |
| 4×4 | 2 | 2 | 4/2 = 2 |
| 5×5 | 3 | 2 | 5/2 = 2 |
| 6×6 | 3 | 3 | 6/2 = 3 |
| 7×7 | 4 | 3 | 7/2 = 3 |
+-----+--------+------------------+---------+
Notice how N/2 matches the number of layers that need to be rotated? Sometimes the number of rotatable layers is one less the total number of layers in the matrix. This occurs when the innermost layer is formed of only one element (i.e. a 1×1 matrix) and therefore need not be rotated. It simply gets ignored.
We will undoubtedly need this information in our function to rotate a matrix, so let’s add it now:
def rotate(matrix):
size = len(matrix)
# Rotatable layers only.
layer_count = size / 2
Now we know what layers are and how to determine the number of layers that actually need rotating, how do we isolate a single layer so we can rotate it? Firstly, we inspect a matrix from the outermost layer, inwards, to the innermost layer. A 5×5 matrix has three layers in total and two layers that need rotating:
. . . . .
. x x x .
. x O x .
. x x x .
. . . . .
Let’s look at columns first. The position of the columns defining the outermost layer, assuming we count from 0, are 0 and 4:
+--------+-----------+
| Column | 0 1 2 3 4 |
+--------+-----------+
| | . . . . . |
| | . x x x . |
| | . x O x . |
| | . x x x . |
| | . . . . . |
+--------+-----------+
0 and 4 are also the positions of the rows for the outermost layer.
+-----+-----------+
| Row | |
+-----+-----------+
| 0 | . . . . . |
| 1 | . x x x . |
| 2 | . x O x . |
| 3 | . x x x . |
| 4 | . . . . . |
+-----+-----------+
This will always be the case since the width and height are the same. Therefore we can define the column and row positions of a layer with just two values (rather than four).
Moving inwards to the second layer, the position of the columns are 1 and 3. And, yes, you guessed it, it’s the same for rows. It’s important to understand we had to both increment and decrement the row and column positions when moving inwards to the next layer.
+-----------+---------+---------+---------+
| Layer | Rows | Columns | Rotate? |
+-----------+---------+---------+---------+
| Outermost | 0 and 4 | 0 and 4 | Yes |
| Inner | 1 and 3 | 1 and 3 | Yes |
| Innermost | 2 | 2 | No |
+-----------+---------+---------+---------+
So, to inspect each layer, we want a loop with both increasing and decreasing counters that represent moving inwards, starting from the outermost layer. We’ll call this our ‘layer loop’.
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
for layer in range(0, layer_count):
first = layer
last = size - first - 1
print 'Layer %d: first: %d, last: %d' % (layer, first, last)
# 5x5 matrix
matrix = [
[ 0, 1, 2, 3, 4],
[ 5, 6, 6, 8, 9],
[10,11,12,13,14],
[15,16,17,18,19],
[20,21,22,23,24]
]
rotate(matrix)
The code above loops through the (row and column) positions of any layers that need rotating.
Layer 0: first: 0, last: 4
Layer 1: first: 1, last: 3
We now have a loop providing the positions of the rows and columns of each layer. The variables first and last identify the index position of the first and last rows and columns. Referring back to our row and column tables:
+--------+-----------+
| Column | 0 1 2 3 4 |
+--------+-----------+
| | . . . . . |
| | . x x x . |
| | . x O x . |
| | . x x x . |
| | . . . . . |
+--------+-----------+
+-----+-----------+
| Row | |
+-----+-----------+
| 0 | . . . . . |
| 1 | . x x x . |
| 2 | . x O x . |
| 3 | . x x x . |
| 4 | . . . . . |
+-----+-----------+
So we can navigate through the layers of a matrix. Now we need a way of navigating within a layer so we can move elements around that layer. Note, elements never ‘jump’ from one layer to another, but they do move within their respective layers.
Rotating each element in a layer rotates the entire layer. Rotating all layers in a matrix rotates the entire matrix. This sentence is very important, so please try your best to understand it before moving on.
Now, we need a way of actually moving elements, i.e. rotate each element, and subsequently the layer, and ultimately the matrix. For simplicity, we’ll revert to a 3x3 matrix — that has one rotatable layer.
0 1 2
3 4 5
6 7 8
Our layer loop provides the indexes of the first and last columns, as well as first and last rows:
+-----+-------+
| Col | 0 1 2 |
+-----+-------+
| | 0 1 2 |
| | 3 4 5 |
| | 6 7 8 |
+-----+-------+
+-----+-------+
| Row | |
+-----+-------+
| 0 | 0 1 2 |
| 1 | 3 4 5 |
| 2 | 6 7 8 |
+-----+-------+
Because our matrices are always square, we need just two variables, first and last, since index positions are the same for rows and columns.
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
# Our layer loop i=0, i=1, i=2
for layer in range(0, layer_count):
first = layer
last = size - first - 1
# We want to move within a layer here.
The variables first and last can easily be used to reference the four corners of a matrix. This is because the corners themselves can be defined using various permutations of first and last (with no subtraction, addition or offset of those variables):
+---------------+-------------------+-------------+
| Corner | Position | 3x3 Values |
+---------------+-------------------+-------------+
| top left | (first, first) | (0,0) |
| top right | (first, last) | (0,2) |
| bottom right | (last, last) | (2,2) |
| bottom left | (last, first) | (2,0) |
+---------------+-------------------+-------------+
For this reason, we start our rotation at the outer four corners — we’ll rotate those first. Let’s highlight them with *.
* 1 *
3 4 5
* 7 *
We want to swap each * with the * to the right of it. So let’s go ahead a print out our corners defined using only various permutations of first and last:
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
for layer in range(0, layer_count):
first = layer
last = size - first - 1
top_left = (first, first)
top_right = (first, last)
bottom_right = (last, last)
bottom_left = (last, first)
print 'top_left: %s' % (top_left)
print 'top_right: %s' % (top_right)
print 'bottom_right: %s' % (bottom_right)
print 'bottom_left: %s' % (bottom_left)
matrix = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]
rotate(matrix)
Output should be:
top_left: (0, 0)
top_right: (0, 2)
bottom_right: (2, 2)
bottom_left: (2, 0)
Now we could quite easily swap each of the corners from within our layer loop:
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
for layer in range(0, layer_count):
first = layer
last = size - first - 1
top_left = matrix[first][first]
top_right = matrix[first][last]
bottom_right = matrix[last][last]
bottom_left = matrix[last][first]
# bottom_left -> top_left
matrix[first][first] = bottom_left
# top_left -> top_right
matrix[first][last] = top_left
# top_right -> bottom_right
matrix[last][last] = top_right
# bottom_right -> bottom_left
matrix[last][first] = bottom_right
print_matrix(matrix)
print '---------'
rotate(matrix)
print_matrix(matrix)
Matrix before rotating corners:
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
Matrix after rotating corners:
[6, 1, 0]
[3, 4, 5]
[8, 7, 2]
Great! We have successfully rotated each corner of the matrix. But, we haven’t rotated the elements in the middle of each layer. Clearly we need a way of iterating within a layer.
The problem is, the only loop in our function so far (our layer loop), moves to the next layer on each iteration. Since our matrix has only one rotatable layer, the layer loop exits after rotating only the corners. Let’s look at what happens with a larger, 5×5 matrix (where two layers need rotating). The function code has been omitted, but it remains the same as above:
matrix = [
[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]
]
print_matrix(matrix)
print '--------------------'
rotate(matrix)
print_matrix(matrix)
The output is:
[20, 1, 2, 3, 0]
[ 5, 16, 7, 6, 9]
[10, 11, 12, 13, 14]
[15, 18, 17, 8, 19]
[24, 21, 22, 23, 4]
It shouldn’t be a surprise that the corners of the outermost layer have been rotated, but, you may also notice the corners of the next layer (inwards) have also been rotated. This makes sense. We’ve written code to navigate through layers and also to rotate the corners of each layer. This feels like progress, but unfortunately we must take a step back. It’s just no good moving onto the next layer until the previous (outer) layer has been fully rotated. That is, until each element in the layer has been rotated. Rotating only the corners won’t do!
Take a deep breath. We need another loop. A nested loop no less. The new, nested loop, will use the first and last variables, plus an offset to navigate within a layer. We’ll call this new loop our ‘element loop’. The element loop will visit each element along the top row, each element down the right side, each element along the bottom row and each element up the left side.
Moving forwards along the top row requires the column
index to be incremented.
Moving down the right side requires the row index to be
incremented.
Moving backwards along the bottom requires the column
index to be decremented.
Moving up the left side requires the row index to be
decremented.
This sounds complex, but it’s made easy because the number of times we increment and decrement to achieve the above remains the same along all four sides of the matrix. For example:
Move 1 element across the top row.
Move 1 element down the right side.
Move 1 element backwards along the bottom row.
Move 1 element up the left side.
This means we can use a single variable in combination with the first and last variables to move within a layer. It may help to note that moving across the top row and down the right side both require incrementing. While moving backwards along the bottom and up the left side both require decrementing.
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
# Move through layers (i.e. layer loop).
for layer in range(0, layer_count):
first = layer
last = size - first - 1
# Move within a single layer (i.e. element loop).
for element in range(first, last):
offset = element - first
# 'element' increments column (across right)
top = (first, element)
# 'element' increments row (move down)
right_side = (element, last)
# 'last-offset' decrements column (across left)
bottom = (last, last-offset)
# 'last-offset' decrements row (move up)
left_side = (last-offset, first)
print 'top: %s' % (top)
print 'right_side: %s' % (right_side)
print 'bottom: %s' % (bottom)
print 'left_side: %s' % (left_side)
Now we simply need to assign the top to the right side, right side to the bottom, bottom to the left side, and left side to the top. Putting this all together we get:
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
for layer in range(0, layer_count):
first = layer
last = size - first - 1
for element in range(first, last):
offset = element - first
top = matrix[first][element]
right_side = matrix[element][last]
bottom = matrix[last][last-offset]
left_side = matrix[last-offset][first]
matrix[first][element] = left_side
matrix[element][last] = top
matrix[last][last-offset] = right_side
matrix[last-offset][first] = bottom
Given the matrix:
0, 1, 2
3, 4, 5
6, 7, 8
Our rotate function results in:
6, 3, 0
7, 4, 1
8, 5, 2
Here it is in C#
int[,] array = new int[4,4] {
{ 1,2,3,4 },
{ 5,6,7,8 },
{ 9,0,1,2 },
{ 3,4,5,6 }
};
int[,] rotated = RotateMatrix(array, 4);
static int[,] RotateMatrix(int[,] matrix, int n) {
int[,] ret = new int[n, n];
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
ret[i, j] = matrix[n - j - 1, i];
}
}
return ret;
}
Python:
rotated = list(zip(*original[::-1]))
and counterclockwise:
rotated_ccw = list(zip(*original))[::-1]
How this works:
zip(*original) will swap axes of 2d arrays by stacking corresponding items from lists into new lists. (The * operator tells the function to distribute the contained lists into arguments)
>>> list(zip(*[[1,2,3],[4,5,6],[7,8,9]]))
[[1,4,7],[2,5,8],[3,6,9]]
The [::-1] statement reverses array elements (please see Extended Slices or this question):
>>> [[1,2,3],[4,5,6],[7,8,9]][::-1]
[[7,8,9],[4,5,6],[1,2,3]]
Finally, combining the two will result in the rotation transformation.
The change in placement of [::-1] will reverse lists in different levels of the matrix.
Here is one that does the rotation in place instead of using a completely new array to hold the result. I've left off initialization of the array and printing it out. This only works for square arrays but they can be of any size. Memory overhead is equal to the size of one element of the array so you can do the rotation of as large an array as you want.
int a[4][4];
int n = 4;
int tmp;
for (int i = 0; i < n / 2; i++)
{
for (int j = i; j < n - i - 1; j++)
{
tmp = a[i][j];
a[i][j] = a[j][n-i-1];
a[j][n-i-1] = a[n-i-1][n-j-1];
a[n-i-1][n-j-1] = a[n-j-1][i];
a[n-j-1][i] = tmp;
}
}
There are tons of good code here but I just want to show what's going on geometrically so you can understand the code logic a little better. Here is how I would approach this.
first of all, do not confuse this with transposition which is very easy..
the basica idea is to treat it as layers and we rotate one layer at a time..
say we have a 4x4
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
after we rotate it clockwise by 90 we get
13 9 5 1
14 10 6 2
15 11 7 3
16 12 8 4
so let's decompose this, first we rotate the 4 corners essentially
1 4
13 16
then we rotate the following diamond which is sort of askew
2
8
9
15
and then the 2nd skewed diamond
3
5
12
14
so that takes care of the outer edge so essentially we do that one shell at a time until
finally the middle square (or if it's odd just the final element which does not move)
6 7
10 11
so now let's figure out the indices of each layer, assume we always work with the outermost layer, we are doing
[0,0] -> [0,n-1], [0,n-1] -> [n-1,n-1], [n-1,n-1] -> [n-1,0], and [n-1,0] -> [0,0]
[0,1] -> [1,n-1], [1,n-2] -> [n-1,n-2], [n-1,n-2] -> [n-2,0], and [n-2,0] -> [0,1]
[0,2] -> [2,n-2], [2,n-2] -> [n-1,n-3], [n-1,n-3] -> [n-3,0], and [n-3,0] -> [0,2]
so on and so on
until we are halfway through the edge
so in general the pattern is
[0,i] -> [i,n-i], [i,n-i] -> [n-1,n-(i+1)], [n-1,n-(i+1)] -> [n-(i+1),0], and [n-(i+1),0] to [0,i]
As I said in my previous post, here's some code in C# that implements an O(1) matrix rotation for any size matrix. For brevity and readability there's no error checking or range checking. The code:
static void Main (string [] args)
{
int [,]
// create an arbitrary matrix
m = {{0, 1}, {2, 3}, {4, 5}};
Matrix
// create wrappers for the data
m1 = new Matrix (m),
m2 = new Matrix (m),
m3 = new Matrix (m);
// rotate the matricies in various ways - all are O(1)
m1.RotateClockwise90 ();
m2.Rotate180 ();
m3.RotateAnitclockwise90 ();
// output the result of transforms
System.Diagnostics.Trace.WriteLine (m1.ToString ());
System.Diagnostics.Trace.WriteLine (m2.ToString ());
System.Diagnostics.Trace.WriteLine (m3.ToString ());
}
class Matrix
{
enum Rotation
{
None,
Clockwise90,
Clockwise180,
Clockwise270
}
public Matrix (int [,] matrix)
{
m_matrix = matrix;
m_rotation = Rotation.None;
}
// the transformation routines
public void RotateClockwise90 ()
{
m_rotation = (Rotation) (((int) m_rotation + 1) & 3);
}
public void Rotate180 ()
{
m_rotation = (Rotation) (((int) m_rotation + 2) & 3);
}
public void RotateAnitclockwise90 ()
{
m_rotation = (Rotation) (((int) m_rotation + 3) & 3);
}
// accessor property to make class look like a two dimensional array
public int this [int row, int column]
{
get
{
int
value = 0;
switch (m_rotation)
{
case Rotation.None:
value = m_matrix [row, column];
break;
case Rotation.Clockwise90:
value = m_matrix [m_matrix.GetUpperBound (0) - column, row];
break;
case Rotation.Clockwise180:
value = m_matrix [m_matrix.GetUpperBound (0) - row, m_matrix.GetUpperBound (1) - column];
break;
case Rotation.Clockwise270:
value = m_matrix [column, m_matrix.GetUpperBound (1) - row];
break;
}
return value;
}
set
{
switch (m_rotation)
{
case Rotation.None:
m_matrix [row, column] = value;
break;
case Rotation.Clockwise90:
m_matrix [m_matrix.GetUpperBound (0) - column, row] = value;
break;
case Rotation.Clockwise180:
m_matrix [m_matrix.GetUpperBound (0) - row, m_matrix.GetUpperBound (1) - column] = value;
break;
case Rotation.Clockwise270:
m_matrix [column, m_matrix.GetUpperBound (1) - row] = value;
break;
}
}
}
// creates a string with the matrix values
public override string ToString ()
{
int
num_rows = 0,
num_columns = 0;
switch (m_rotation)
{
case Rotation.None:
case Rotation.Clockwise180:
num_rows = m_matrix.GetUpperBound (0);
num_columns = m_matrix.GetUpperBound (1);
break;
case Rotation.Clockwise90:
case Rotation.Clockwise270:
num_rows = m_matrix.GetUpperBound (1);
num_columns = m_matrix.GetUpperBound (0);
break;
}
StringBuilder
output = new StringBuilder ();
output.Append ("{");
for (int row = 0 ; row <= num_rows ; ++row)
{
if (row != 0)
{
output.Append (", ");
}
output.Append ("{");
for (int column = 0 ; column <= num_columns ; ++column)
{
if (column != 0)
{
output.Append (", ");
}
output.Append (this [row, column].ToString ());
}
output.Append ("}");
}
output.Append ("}");
return output.ToString ();
}
int [,]
// the original matrix
m_matrix;
Rotation
// the current view of the matrix
m_rotation;
}
OK, I'll put my hand up, it doesn't actually do any modifications to the original array when rotating. But, in an OO system that doesn't matter as long as the object looks like it's been rotated to the clients of the class. At the moment, the Matrix class uses references to the original array data so changing any value of m1 will also change m2 and m3. A small change to the constructor to create a new array and copy the values to it will sort that out.
Whilst rotating the data in place might be necessary (perhaps to update the physically stored representation), it becomes simpler and possibly more performant to add a layer of indirection onto the array access, perhaps an interface:
interface IReadableMatrix
{
int GetValue(int x, int y);
}
If your Matrix already implements this interface, then it can be rotated via a decorator class like this:
class RotatedMatrix : IReadableMatrix
{
private readonly IReadableMatrix _baseMatrix;
public RotatedMatrix(IReadableMatrix baseMatrix)
{
_baseMatrix = baseMatrix;
}
int GetValue(int x, int y)
{
// transpose x and y dimensions
return _baseMatrix(y, x);
}
}
Rotating +90/-90/180 degrees, flipping horizontally/vertically and scaling can all be achieved in this fashion as well.
Performance would need to be measured in your specific scenario. However the O(n^2) operation has now been replaced with an O(1) call. It's a virtual method call which is slower than direct array access, so it depends upon how frequently the rotated array is used after rotation. If it's used once, then this approach would definitely win. If it's rotated then used in a long-running system for days, then in-place rotation might perform better. It also depends whether you can accept the up-front cost.
As with all performance issues, measure, measure, measure!
This a better version of it in Java: I've made it for a matrix with a different width and height
h is here the height of the matrix after rotating
w is here the width of the matrix after rotating
public int[][] rotateMatrixRight(int[][] matrix)
{
/* W and H are already swapped */
int w = matrix.length;
int h = matrix[0].length;
int[][] ret = new int[h][w];
for (int i = 0; i < h; ++i) {
for (int j = 0; j < w; ++j) {
ret[i][j] = matrix[w - j - 1][i];
}
}
return ret;
}
public int[][] rotateMatrixLeft(int[][] matrix)
{
/* W and H are already swapped */
int w = matrix.length;
int h = matrix[0].length;
int[][] ret = new int[h][w];
for (int i = 0; i < h; ++i) {
for (int j = 0; j < w; ++j) {
ret[i][j] = matrix[j][h - i - 1];
}
}
return ret;
}
This code is based on Nick Berardi's post.
Ruby-way: .transpose.map &:reverse
There are a lot of answers already, and I found two claiming O(1) time complexity. The real O(1) algorithm is to leave the array storage untouched, and change how you index its elements. The goal here is that it does not consume additional memory, nor does it require additional time to iterate the data.
Rotations of 90, -90 and 180 degrees are simple transformations which can be performed as long as you know how many rows and columns are in your 2D array; To rotate any vector by 90 degrees, swap the axes and negate the Y axis. For -90 degree, swap the axes and negate the X axis. For 180 degrees, negate both axes without swapping.
Further transformations are possible, such as mirroring horizontally and/or vertically by negating the axes independently.
This can be done through e.g. an accessor method. The examples below are JavaScript functions, but the concepts apply equally to all languages.
// Get an array element in column/row order
var getArray2d = function(a, x, y) {
return a[y][x];
};
//demo
var arr = [
[5, 4, 6],
[1, 7, 9],
[-2, 11, 0],
[8, 21, -3],
[3, -1, 2]
];
var newarr = [];
arr[0].forEach(() => newarr.push(new Array(arr.length)));
for (var i = 0; i < newarr.length; i++) {
for (var j = 0; j < newarr[0].length; j++) {
newarr[i][j] = getArray2d(arr, i, j);
}
}
console.log(newarr);
// Get an array element rotated 90 degrees clockwise
function getArray2dCW(a, x, y) {
var t = x;
x = y;
y = a.length - t - 1;
return a[y][x];
}
//demo
var arr = [
[5, 4, 6],
[1, 7, 9],
[-2, 11, 0],
[8, 21, -3],
[3, -1, 2]
];
var newarr = [];
arr[0].forEach(() => newarr.push(new Array(arr.length)));
for (var i = 0; i < newarr[0].length; i++) {
for (var j = 0; j < newarr.length; j++) {
newarr[j][i] = getArray2dCW(arr, i, j);
}
}
console.log(newarr);
// Get an array element rotated 90 degrees counter-clockwise
function getArray2dCCW(a, x, y) {
var t = x;
x = a[0].length - y - 1;
y = t;
return a[y][x];
}
//demo
var arr = [
[5, 4, 6],
[1, 7, 9],
[-2, 11, 0],
[8, 21, -3],
[3, -1, 2]
];
var newarr = [];
arr[0].forEach(() => newarr.push(new Array(arr.length)));
for (var i = 0; i < newarr[0].length; i++) {
for (var j = 0; j < newarr.length; j++) {
newarr[j][i] = getArray2dCCW(arr, i, j);
}
}
console.log(newarr);
// Get an array element rotated 180 degrees
function getArray2d180(a, x, y) {
x = a[0].length - x - 1;
y = a.length - y - 1;
return a[y][x];
}
//demo
var arr = [
[5, 4, 6],
[1, 7, 9],
[-2, 11, 0],
[8, 21, -3],
[3, -1, 2]
];
var newarr = [];
arr.forEach(() => newarr.push(new Array(arr[0].length)));
for (var i = 0; i < newarr[0].length; i++) {
for (var j = 0; j < newarr.length; j++) {
newarr[j][i] = getArray2d180(arr, i, j);
}
}
console.log(newarr);
This code assumes an array of nested arrays, where each inner array is a row.
The method allows you to read (or write) elements (even in random order) as if the array has been rotated or transformed. Now just pick the right function to call, probably by reference, and away you go!
The concept can be extended to apply transformations additively (and non-destructively) through the accessor methods. Including arbitrary angle rotations and scaling.
A couple of people have already put up examples which involve making a new array.
A few other things to consider:
(a) Instead of actually moving the data, simply traverse the "rotated" array differently.
(b) Doing the rotation in-place can be a little trickier. You'll need a bit of scratch place (probably roughly equal to one row or column in size). There's an ancient ACM paper about doing in-place transposes (http://doi.acm.org/10.1145/355719.355729), but their example code is nasty goto-laden FORTRAN.
Addendum:
http://doi.acm.org/10.1145/355611.355612 is another, supposedly superior, in-place transpose algorithm.
Nick's answer would work for an NxM array too with only a small modification (as opposed to an NxN).
string[,] orig = new string[n, m];
string[,] rot = new string[m, n];
...
for ( int i=0; i < n; i++ )
for ( int j=0; j < m; j++ )
rot[j, n - i - 1] = orig[i, j];
One way to think about this is that you have moved the center of the axis (0,0) from the top left corner to the top right corner. You're simply transposing from one to the other.
Time - O(N), Space - O(1)
public void rotate(int[][] matrix) {
int n = matrix.length;
for (int i = 0; i < n / 2; i++) {
int last = n - 1 - i;
for (int j = i; j < last; j++) {
int top = matrix[i][j];
matrix[i][j] = matrix[last - j][i];
matrix[last - j][i] = matrix[last][last - j];
matrix[last][last - j] = matrix[j][last];
matrix[j][last] = top;
}
}
}
A common method to rotate a 2D array clockwise or anticlockwise.
clockwise rotate
first reverse up to down, then swap the symmetry
1 2 3 7 8 9 7 4 1
4 5 6 => 4 5 6 => 8 5 2
7 8 9 1 2 3 9 6 3
void rotate(vector<vector<int> > &matrix) {
reverse(matrix.begin(), matrix.end());
for (int i = 0; i < matrix.size(); ++i) {
for (int j = i + 1; j < matrix[i].size(); ++j)
swap(matrix[i][j], matrix[j][i]);
}
}
anticlockwise rotate
first reverse left to right, then swap the symmetry
1 2 3 3 2 1 3 6 9
4 5 6 => 6 5 4 => 2 5 8
7 8 9 9 8 7 1 4 7
void anti_rotate(vector<vector<int> > &matrix) {
for (auto vi : matrix) reverse(vi.begin(), vi.end());
for (int i = 0; i < matrix.size(); ++i) {
for (int j = i + 1; j < matrix[i].size(); ++j)
swap(matrix[i][j], matrix[j][i]);
}
}
Here's my Ruby version (note the values aren't displayed the same, but it still rotates as described).
def rotate(matrix)
result = []
4.times { |x|
result[x] = []
4.times { |y|
result[x][y] = matrix[y][3 - x]
}
}
result
end
matrix = []
matrix[0] = [1,2,3,4]
matrix[1] = [5,6,7,8]
matrix[2] = [9,0,1,2]
matrix[3] = [3,4,5,6]
def print_matrix(matrix)
4.times { |y|
4.times { |x|
print "#{matrix[x][y]} "
}
puts ""
}
end
print_matrix(matrix)
puts ""
print_matrix(rotate(matrix))
The output:
1 5 9 3
2 6 0 4
3 7 1 5
4 8 2 6
4 3 2 1
8 7 6 5
2 1 0 9
6 5 4 3
here's a in-space rotate method, by java, only for square. for non-square 2d array, you will have to create new array anyway.
private void rotateInSpace(int[][] arr) {
int z = arr.length;
for (int i = 0; i < z / 2; i++) {
for (int j = 0; j < (z / 2 + z % 2); j++) {
int x = i, y = j;
int temp = arr[x][y];
for (int k = 0; k < 4; k++) {
int temptemp = arr[y][z - x - 1];
arr[y][z - x - 1] = temp;
temp = temptemp;
int tempX = y;
y = z - x - 1;
x = tempX;
}
}
}
}
code to rotate any size 2d array by creating new array:
private int[][] rotate(int[][] arr) {
int width = arr[0].length;
int depth = arr.length;
int[][] re = new int[width][depth];
for (int i = 0; i < depth; i++) {
for (int j = 0; j < width; j++) {
re[j][depth - i - 1] = arr[i][j];
}
}
return re;
}
You can do this in 3 easy steps:
1)Suppose we have a matrix
1 2 3
4 5 6
7 8 9
2)Take the transpose of the matrix
1 4 7
2 5 8
3 6 9
3)Interchange rows to get rotated matrix
3 6 9
2 5 8
1 4 7
Java source code for this:
public class MyClass {
public static void main(String args[]) {
Demo obj = new Demo();
/*initial matrix to rotate*/
int[][] matrix = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
int[][] transpose = new int[3][3]; // matrix to store transpose
obj.display(matrix); // initial matrix
obj.rotate(matrix, transpose); // call rotate method
System.out.println();
obj.display(transpose); // display the rotated matix
}
}
class Demo {
public void rotate(int[][] mat, int[][] tran) {
/* First take the transpose of the matrix */
for (int i = 0; i < mat.length; i++) {
for (int j = 0; j < mat.length; j++) {
tran[i][j] = mat[j][i];
}
}
/*
* Interchange the rows of the transpose matrix to get rotated
* matrix
*/
for (int i = 0, j = tran.length - 1; i != j; i++, j--) {
for (int k = 0; k < tran.length; k++) {
swap(i, k, j, k, tran);
}
}
}
public void swap(int a, int b, int c, int d, int[][] arr) {
int temp = arr[a][b];
arr[a][b] = arr[c][d];
arr[c][d] = temp;
}
/* Method to display the matrix */
public void display(int[][] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
}
Output:
1 2 3
4 5 6
7 8 9
3 6 9
2 5 8
1 4 7
Implementation of dimple's +90 pseudocode (e.g. transpose then reverse each row) in JavaScript:
function rotate90(a){
// transpose from http://www.codesuck.com/2012/02/transpose-javascript-array-in-one-line.html
a = Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
// row reverse
for (i in a){
a[i] = a[i].reverse();
}
return a;
}
In python:
import numpy as np
a = np.array(
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 0, 1, 2],
[3, 4, 5, 6]
]
)
print(a)
print(b[::-1, :].T)
This is my implementation, in C, O(1) memory complexity, in place rotation, 90 degrees clockwise:
#include <stdio.h>
#define M_SIZE 5
static void initMatrix();
static void printMatrix();
static void rotateMatrix();
static int m[M_SIZE][M_SIZE];
int main(void){
initMatrix();
printMatrix();
rotateMatrix();
printMatrix();
return 0;
}
static void initMatrix(){
int i, j;
for(i = 0; i < M_SIZE; i++){
for(j = 0; j < M_SIZE; j++){
m[i][j] = M_SIZE*i + j + 1;
}
}
}
static void printMatrix(){
int i, j;
printf("Matrix\n");
for(i = 0; i < M_SIZE; i++){
for(j = 0; j < M_SIZE; j++){
printf("%02d ", m[i][j]);
}
printf("\n");
}
printf("\n");
}
static void rotateMatrix(){
int r, c;
for(r = 0; r < M_SIZE/2; r++){
for(c = r; c < M_SIZE - r - 1; c++){
int tmp = m[r][c];
m[r][c] = m[M_SIZE - c - 1][r];
m[M_SIZE - c - 1][r] = m[M_SIZE - r - 1][M_SIZE - c - 1];
m[M_SIZE - r - 1][M_SIZE - c - 1] = m[c][M_SIZE - r - 1];
m[c][M_SIZE - r - 1] = tmp;
}
}
}
Here is the Java version:
public static void rightRotate(int[][] matrix, int n) {
for (int layer = 0; layer < n / 2; layer++) {
int first = layer;
int last = n - 1 - first;
for (int i = first; i < last; i++) {
int offset = i - first;
int temp = matrix[first][i];
matrix[first][i] = matrix[last-offset][first];
matrix[last-offset][first] = matrix[last][last-offset];
matrix[last][last-offset] = matrix[i][last];
matrix[i][last] = temp;
}
}
}
the method first rotate the mostouter layer, then move to the inner layer squentially.
From a linear point of view, consider the matrices:
1 2 3 0 0 1
A = 4 5 6 B = 0 1 0
7 8 9 1 0 0
Now take A transpose
1 4 7
A' = 2 5 8
3 6 9
And consider the action of A' on B, or B on A'.
Respectively:
7 4 1 3 6 9
A'B = 8 5 2 BA' = 2 5 8
9 6 3 1 4 7
This is expandable for any n x n matrix.
And applying this concept quickly in code:
void swapInSpace(int** mat, int r1, int c1, int r2, int c2)
{
mat[r1][c1] ^= mat[r2][c2];
mat[r2][c2] ^= mat[r1][c1];
mat[r1][c1] ^= mat[r2][c2];
}
void transpose(int** mat, int size)
{
for (int i = 0; i < size; i++)
{
for (int j = (i + 1); j < size; j++)
{
swapInSpace(mat, i, j, j, i);
}
}
}
void rotate(int** mat, int size)
{
//Get transpose
transpose(mat, size);
//Swap columns
for (int i = 0; i < size / 2; i++)
{
for (int j = 0; j < size; j++)
{
swapInSpace(mat, i, j, size - (i + 1), j);
}
}
}
C# code to rotate [n,m] 2D arrays 90 deg right
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MatrixProject
{
// mattrix class
class Matrix{
private int rows;
private int cols;
private int[,] matrix;
public Matrix(int n){
this.rows = n;
this.cols = n;
this.matrix = new int[this.rows,this.cols];
}
public Matrix(int n,int m){
this.rows = n;
this.cols = m;
this.matrix = new int[this.rows,this.cols];
}
public void Show()
{
for (var i = 0; i < this.rows; i++)
{
for (var j = 0; j < this.cols; j++) {
Console.Write("{0,3}", this.matrix[i, j]);
}
Console.WriteLine();
}
}
public void ReadElements()
{
for (var i = 0; i < this.rows; i++)
for (var j = 0; j < this.cols; j++)
{
Console.Write("element[{0},{1}]=",i,j);
this.matrix[i, j] = Convert.ToInt32(Console.ReadLine());
}
}
// rotate [n,m] 2D array by 90 deg right
public void Rotate90DegRight()
{
// create a mirror of current matrix
int[,] mirror = this.matrix;
// create a new matrix
this.matrix = new int[this.cols, this.rows];
for (int i = 0; i < this.rows; i++)
{
for (int j = 0; j < this.cols; j++)
{
this.matrix[j, this.rows - i - 1] = mirror[i, j];
}
}
// replace cols count with rows count
int tmp = this.rows;
this.rows = this.cols;
this.cols = tmp;
}
}
class Program
{
static void Main(string[] args)
{
Matrix myMatrix = new Matrix(3,4);
Console.WriteLine("Enter matrix elements:");
myMatrix.ReadElements();
Console.WriteLine("Matrix elements are:");
myMatrix.Show();
myMatrix.Rotate90DegRight();
Console.WriteLine("Matrix rotated at 90 deg are:");
myMatrix.Show();
Console.ReadLine();
}
}
}
Result:
Enter matrix elements:
element[0,0]=1
element[0,1]=2
element[0,2]=3
element[0,3]=4
element[1,0]=5
element[1,1]=6
element[1,2]=7
element[1,3]=8
element[2,0]=9
element[2,1]=10
element[2,2]=11
element[2,3]=12
Matrix elements are:
1 2 3 4
5 6 7 8
9 10 11 12
Matrix rotated at 90 deg are:
9 5 1
10 6 2
11 7 3
12 8 4
Great answers but for those who are looking for a DRY JavaScript code for this - both +90 Degrees and -90 Degrees:
// Input: 1 2 3
// 4 5 6
// 7 8 9
// Transpose:
// 1 4 7
// 2 5 8
// 3 6 9
// Output:
// +90 Degree:
// 7 4 1
// 8 5 2
// 9 6 3
// -90 Degree:
// 3 6 9
// 2 5 8
// 1 4 7
// Rotate +90
function rotate90(matrix) {
matrix = transpose(matrix);
matrix.map(function(array) {
array.reverse();
});
return matrix;
}
// Rotate -90
function counterRotate90(matrix) {
var result = createEmptyMatrix(matrix.length);
matrix = transpose(matrix);
var counter = 0;
for (var i = matrix.length - 1; i >= 0; i--) {
result[counter] = matrix[i];
counter++;
}
return result;
}
// Create empty matrix
function createEmptyMatrix(len) {
var result = new Array();
for (var i = 0; i < len; i++) {
result.push([]);
}
return result;
}
// Transpose the matrix
function transpose(matrix) {
// make empty array
var len = matrix.length;
var result = createEmptyMatrix(len);
for (var i = 0; i < matrix.length; i++) {
for (var j = 0; j < matrix[i].length; j++) {
var temp = matrix[i][j];
result[j][i] = temp;
}
}
return result;
}
// Test Cases
var array1 = [
[1, 2],
[3, 4]
];
var array2 = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
var array3 = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
];
// +90 degress Rotation Tests
var test1 = rotate90(array1);
var test2 = rotate90(array2);
var test3 = rotate90(array3);
console.log(test1);
console.log(test2);
console.log(test3);
// -90 degress Rotation Tests
var test1 = counterRotate90(array1);
var test2 = counterRotate90(array2);
var test3 = counterRotate90(array3);
console.log(test1);
console.log(test2);
console.log(test3);
PHP:
<?php
$a = array(array(1,2,3,4),array(5,6,7,8),array(9,0,1,2),array(3,4,5,6));
$b = array(); //result
while(count($a)>0)
{
$b[count($a[0])-1][] = array_shift($a[0]);
if (count($a[0])==0)
{
array_shift($a);
}
}
From PHP5.6, Array transposition can be performed with a sleak array_map() call. In other words, columns are converted to rows.
Code: (Demo)
$array = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 0, 1, 2],
[3, 4, 5, 6]
];
$transposed = array_map(null, ...$array);
$transposed:
[
[1, 5, 9, 3],
[2, 6, 0, 4],
[3, 7, 1, 5],
[4, 8, 2, 6]
]
For i:= 0 to X do
For j := 0 to X do
graphic[j][i] := graphic2[X-i][j]
X is the size of the array the graphic is in.
#transpose is a standard method of Ruby's Array class, thus:
% irb
irb(main):001:0> m = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 0, 1, 2], [3, 4, 5, 6]]
=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 0, 1, 2], [3, 4, 5, 6]]
irb(main):002:0> m.reverse.transpose
=> [[3, 9, 5, 1], [4, 0, 6, 2], [5, 1, 7, 3], [6, 2, 8, 4]]
The implementation is an n^2 transposition function written in C. You can see it here:
http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-transpose
by choosing "click to toggle source" beside "transpose".
I recall better than O(n^2) solutions, but only for specially constructed matrices (such as sparse matrices)
C code for matrix rotation 90 degree clockwise IN PLACE for any M*N matrix
void rotateInPlace(int * arr[size][size], int row, int column){
int i, j;
int temp = row>column?row:column;
int flipTill = row < column ? row : column;
for(i=0;i<flipTill;i++){
for(j=0;j<i;j++){
swapArrayElements(arr, i, j);
}
}
temp = j+1;
for(i = row>column?i:0; i<row; i++){
for(j=row<column?temp:0; j<column; j++){
swapArrayElements(arr, i, j);
}
}
for(i=0;i<column;i++){
for(j=0;j<row/2;j++){
temp = arr[i][j];
arr[i][j] = arr[i][row-j-1];
arr[i][row-j-1] = temp;
}
}
}
here is my In Place implementation in C
void rotateRight(int matrix[][SIZE], int length) {
int layer = 0;
for (int layer = 0; layer < length / 2; ++layer) {
int first = layer;
int last = length - 1 - layer;
for (int i = first; i < last; ++i) {
int topline = matrix[first][i];
int rightcol = matrix[i][last];
int bottomline = matrix[last][length - layer - 1 - i];
int leftcol = matrix[length - layer - 1 - i][first];
matrix[first][i] = leftcol;
matrix[i][last] = topline;
matrix[last][length - layer - 1 - i] = rightcol;
matrix[length - layer - 1 - i][first] = bottomline;
}
}
}

Resources