I've puzzled over this not usual task for a days to figure out an appropriate algorithm. Let's say I have 2D array:
int[][] jagged = new int[4][];
jagged[0] = new int[4] { 1, 2, 3, 4 };
jagged[1] = new int[4] { 5, 6, 7, 8 };
jagged[2] = new int[4] { 9, 10, 11, 12 };
jagged[3] = new int[4] { 13, 14, 15, 16 };
How can I rotate this matrix in counter-clockwise direction to be like the following?
1 2 3 4 2 3 4 8 3 4 8 12
5 6 7 8 --> 1 7 11 12 --> 2 11 10 16
9 10 11 12 5 6 10 16 1 7 6 15
13 14 15 16 9 13 14 15 5 9 13 14
2D array can have various dimensions. I mean 2x3, or 3x4.
I've tried to use the following algorithm, but it rotates just to 90 degrees:
int [,] newArray = new int[4,4];
for (int i=3;i>=0;--i)
{
for (int j=0;j<4;++j)
{
newArray[j,3-i] = array[i,j];
}
}
If I change increments, then it does give me nothing. Maybe is there another solution?
Assuming each "square" of an array rotates independently.
You could use the following code snippet:
const int ArraySize = 4;
int[,] array =
{
{ 2, 3, 4, 8 },
{ 1, 7, 11, 12 },
{ 5, 6, 10, 16 },
{ 9, 13, 14, 15 }
};
for (int r = (ArraySize - 1) / 2; r >= 0; r--)
{
int start = r;
int end = ArraySize - r - 1;
int saveTopLeft = array[start, start];
// Top
for (int i = start; i <= end - 1; i++)
array[start, i] = array[start, i + 1];
// Right
for (int i = start; i <= end - 1; i++)
array[i, end] = array[i + 1, end];
// Bottom
for (int i = end; i >= start + 1; i--)
array[end, i] = array[end, i - 1];
// Left
for (int i = end; i >= start + 2; i--)
array[i, start] = array[i - 1, start];
// Saved element
array[start + 1, start] = saveTopLeft;
}
I know this question is answered but I wanted to do it for a general matrix of nxm. It takes into account the corner cases where the matrix has only one column or row.
public static void Rotate(int[,] matrix)
{
// Specific cases when matrix has one only row or column
if (matrix.GetLength(0) == 1 || matrix.GetLength(1) == 1)
RotateOneRowOrColumn(matrix);
else
{
int min = Math.Min(matrix.GetLength(0), matrix.GetLength(1)),
b = min / 2, r = min % 2;
for (int d = 0; d < b + r; d++)
{
int bkp = matrix[d, d];
ShiftRow(matrix, d, d, matrix.GetLength(1) - d - 1, true);
ShiftColumn(matrix, matrix.GetLength(1) - d - 1, d, matrix.GetLength(0) - d - 1, false);
ShiftRow(matrix, matrix.GetLength(0) - d - 1, d, matrix.GetLength(1) - d - 1, false);
ShiftColumn(matrix, d, d + 1, matrix.GetLength(0) - d - 1, true);
if (matrix.GetLength(0) - 2 * d - 1 >= 1)
matrix[d + 1, d] = bkp;
}
}
}
private static void RotateOneRowOrColumn(int[,] matrix)
{
bool isRow = matrix.GetLength(0) == 1;
int s = 0, e = (isRow ? matrix.GetLength(1) : matrix.GetLength(0)) - 1;
while (s < e)
{
if (isRow)
Swap(matrix, 0, s, 0, e);
else
Swap(matrix, s, 0, e, 0);
s++; e--;
}
}
public static void Swap(int[,] matrix, int from_x, int from_y, int to_x, int to_y)
{
//It doesn't verifies whether the indices are correct or not
int bkp = matrix[to_x, to_y];
matrix[to_x, to_y] = matrix[from_x, from_y];
matrix[from_x, from_y] = bkp;
}
public static void ShiftColumn(int[,] matrix, int col, int start, int end, bool down)
{
for (int i = down ? end - 1 : start + 1; (down && i >= start) || (!down && i <= end); i += down ? -1 : 1)
{ matrix[i + (down ? 1 : -1), col] = matrix[i, col]; }
}
public static void ShiftRow(int[,] matrix, int row, int start, int end, bool left)
{
for (int j = left ? start + 1 : end - 1; (left && j <= end) || (!left && j >= start); j += (left ? 1 : -1))
{ matrix[row, j + (left ? -1 : 1)] = matrix[row, j]; }
}
Related
I always have to close Unity through Task-Manager if I call this function through a button, what is wrong with my code? I know there are is a lot of processing required for this code but the process never finishes:
public void SudokuLösen()
{
for(int p = 1; p < 81; p++)
{
if(PositionWert[p] != 0){
for(int z = 1; z < 9; z++)
{
if(PositionWert[p] == z)
{
int Reihe = 0;
int Spalte = 0;
int Platz = 0;
for(int m = 0; m < 8; m++)
{
for(int r = 1; r < 9; r++)
{
if(p - m * 9 == r)
{
Reihe = r;
}
}
}
for(int s = 0; s < 9; s++)
{
if(p == Reihe * 9 - 9 + s )
{
s = Spalte;
}
}
for(int g = -8; g < 8; g++)
{
if((Spalte + g > 0) && (Spalte + g < 10))
{
Blockiert[(p + z * 81 - 81) + g] = true;
}
if((Reihe + g > 0) && (Reihe + g < 10))
{
Blockiert[(p + z * 81 - 81) + g * 9] = true;
}
}
for(int vx = 1; vx < 3; vx++)
{
if((Spalte == 0 + vx) || (Spalte == 3 + vx) || (Spalte == 6 + vx))
{
Platz += vx;
}
if((Reihe == 0 + vx) || (Reihe == 3 + vx) || (Reihe == 6 + vx))
{
Platz += (3 * vx - 3);
}
}
for(int q = 1; q < 4; q++)
{
Blockiert[(p + z * 81 - 81) + Quadrat[Platz * 4 - 4 + q]] = true;
}
}
}
}
}
}
}
the Arrays are defined like this:
public static bool[] Blockiert = new bool[730];
public static int[] PositionWert = new int[82];
private int[] Quadrat = {0, 10, 11, 19, 20, 8, 10, 17, 19, 7, 8, 16, 17, -8, -7, 10, 11, -10, -8, 8, 10, -11, -10, 7, 8, -17, -16, -8, -7, -19, -17, -10, -8, -20, -19, -11, -10};
I thought that it might just be because my computer would just take forever to call this function so I waited a long time and saw that Unity nearly used 15% of my CPU so it didn't really do much and the function processing just doesn't finish.
Does anyone know what is wrong or what I should change?
A freeze usually means you have a never ending loop somewhere.
All your loops are finite and there is nothing that should take longer than a couple of milliseconds - except one!
You have
for(int s = 0; s < 9; s++)
{
if(p == Reihe * 9 - 9 + s)
{
s = Spalte;
}
}
where you reassign s = 0 since Spalte was never assigned differently. So you restart the loop and if this condition is met once then it will definitely be met in a future iteration as well since none of the other parameters change within that loop => never ending loop.
Judging from the rest of your code it should probably rather be
Spalte = s;
I need to solve a problem in which I need to split arrays into two sub-arrays such that the sum of their weights will be equal or "nearly equal".
Explanation
If I have an array [1,2,3,4,5] so I can possibly make two subsets of [1,2,4] = 7 and [3,5] = 8 OR [2,5] = 7 and [1,3,4] = 8.
I have done that part but by dry run i got to know that if i have even number of digits in the set of array then it always gives me wrong answers.
This program only works for odd number of digits. What am i missing?
using System.IO;
using System;
class Program
{
static void Main()
{
int[] a = {1,2,3,4};
int t;
Console.WriteLine("Original array :");
foreach (int aa in a)
Console.Write(aa + " ");
for (int p = 0; p <= a.Length - 2; p++)
{
for (int i = 0; i <= a.Length - 2; i++)
{
if (a[i] > a[i + 1])
{
t = a[i + 1];
a[i + 1] = a[i];
a[i] = t;
}
}
}
Console.WriteLine("\n" + "Sorted array :");
foreach (int aa in a)
Console.Write(aa + " ");
Console.Write("\n");
// int[] arr = new int[5] { 99, 95, 93, 89, 87 };
int z, max, min, n;
// size of the array
n = 4;
max = a[0];
min = a[0];
for (z = 1; z < n; z++)
{
if (a[z] > max)
{
max = a[z];
}
if (a[z] < min)
{
min = a[z];
}
}
Console.Write("Maximum element = {0}\n", max);
Console.Write("Minimum element = {0}\n\n", min);
int e = 0;
int f = 0;
int g = 0;
for(int i = 0; i < n; i++)
{
g = f - e;
int mm = max - min;
{
if(g > mm)
{
e += a[i];
}
else if(g < mm)
{
f += a[i];
}
}
min++;
}
Console.Write("The possible solution is:\n ");
Console.Write("First array = {0}\n", e);
Console.Write("Second array = {0}\n\n", f);
Console.ReadLine();
}
}
Here's a code snippet that might help:
var arr = new[] { 1, 2, 3, 4 };
var lst1 = new List<int>();
var lst2 = new List<int>();
var div = Math.DivRem(arr.Sum(), 2, out _);
foreach (var i in arr.OrderByDescending(x => x))
{
if (lst1.Sum() + i <= div)
lst1.Add(i);
else
lst2.Add(i);
}
Console.WriteLine(string.Join(", ", lst1.OrderBy(x => x)));
Console.WriteLine(string.Join(", ", lst2.OrderBy(x => x)));
Some outputs of:
{ 1, 2, 3, 4 }
1, 4
2, 3
{ 1, 2, 3, 4, 5 }
2, 5
1, 3, 4
{ 1, 2, 3, 4, 5, 6 }
4, 6
1, 2, 3, 5
So we iterated through the source array (arr) in a descending order to add numbers into lst1 if the sum of it's contents still less than or equal to the quotient of dividing the sum of the main array by 2, otherwise we add them (the numbers) into lst2 where the sum of it's numbers is equal or nearly equal to the mentioned quotient.
As a result, you have two lists where the sum of their contents are equal or nearly equal.
Below code will split array into 2 with equal sum or least difference in sum.
Apologies for lengthy solution, but it works perfectly for all combinations of odd and even.
Explicit names of variables and functions will help you to understand the logic.
using System.IO;
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main(string[] input)
{
int[] a = {1, 2, 9, 26, 3, 4, 12, 7, 5};
int t;
Console.WriteLine("Original array :" + string.Join(", ", a));
for (int p = 0; p <= a.Length - 2; p++)
{
for (int i = 0; i <= a.Length - 2; i++)
{
if (a[i] > a[i + 1])
{
t = a[i + 1];
a[i + 1] = a[i];
a[i] = t;
}
}
}
Console.WriteLine("\n\nSorted array :" + string.Join(", ", a));
// Newly added code starts
int[] sortedArray = a;
List<int> array1 = new List<int>();
List<int> array2 = new List<int>();
for (int index = sortedArray.Length-1 ; index >=0 ; index-- )
{
if (array1.Sum() < array2.Sum())
{
array1.Add(sortedArray[index]);
}
else if (array1.Sum() > array2.Sum())
{
array2.Add(sortedArray[index]);
}
else
{
array1.Add(sortedArray[index]);
}
}
BalanceArray(array1, array2);
array1.Sort();
array2.Sort();
Console.WriteLine("\n\nArray1 { " + string.Join(", ", array1) + " }\tSum => " + array1.Sum());
Console.WriteLine("\n\nArray2 { " + string.Join(", ", array2) + " }\tSum => " + array2.Sum());
}
private static void BalanceArray(List<int> array1, List<int> array2)
{
int sumOfArray1 = array1.Sum();
int sumOfArray2= array2.Sum();
int difference = (sumOfArray1 < sumOfArray2) ? sumOfArray2- sumOfArray1 : sumOfArray1 - sumOfArray2;
if ( sumOfArray1 < sumOfArray2 )
{
SwapNumber(array2, array1, difference);
}
else if ( sumOfArray1 > sumOfArray2 )
{
SwapNumber(array1, array2, difference);
}
}
private static void SwapNumber(List<int> biggerArray,List<int> smallerArray, int difference)
{
//Console.Write("\n Difference :" + difference);
int expectedDifference = difference /2;
//Console.Write("\n Expected Difference :" + expectedDifference );
int lowerNoToSwap = 0;
int higherNoToSwap = 0;
for(int i=0; i < biggerArray.Count(); i++ )
{
if(biggerArray[i] <= expectedDifference)
{
lowerNoToSwap = biggerArray[i];
}
else if(biggerArray[i] > expectedDifference)
{
higherNoToSwap = biggerArray[i];
break;
}
}
if(lowerNoToSwap <= higherNoToSwap)
{
bool swapLower = (expectedDifference - lowerNoToSwap) < (higherNoToSwap - expectedDifference) ? true : false;
int numberToSwap = swapLower ? lowerNoToSwap : higherNoToSwap;
if(numberToSwap != 0)
{
smallerArray.Add(numberToSwap);
smallerArray.Sort();
biggerArray.Remove(numberToSwap);
}
}
}
}
Example 1
Original array :1, 2, 3, 4
Sorted array :1, 2, 3, 4
before Array1 { 4, 1 } Sum => 5
before Array2 { 3, 2 } Sum => 5
Array1 { 1, 4 } Sum => 5
Array2 { 2, 3 } Sum => 5
Example 2
Original array :1, 2, 3, 4, 5
Sorted array :1, 2, 3, 4, 5
Array1 { 3, 5 } Sum => 8
Array2 { 1, 2, 4 } Sum => 7
Example 3
Original array :1, 2, 9, 26, 3, 4, 12, 7, 5
Sorted array :1, 2, 3, 4, 5, 7, 9, 12, 26
Array1 { 1, 3, 5, 26 } Sum => 35
Array2 { 2, 4, 7, 9, 12 } Sum => 34
I make this code to print array if the number of array is
{
1, 2, 3, 4, 5,
6, 7, 8, 9,
10,11,12,13,
14,15,16,17,
18,19,20,21,
22,23,24,25
}
the out put of this code is
1,2,6,3,7,11,4,6,12,16,5,9,13,17,21,10,14,18,21,15,19,23,20,24,25
I want to make change in this my code to be the out put begging from
21 16 22 11 17 23 6 12 18 24 1 7 13 19 25 2 8 14 203 9 15 4 10 5
and this my Code
int [,] p = new int [5,5];
int sum = 1;
for (int i = 1; i <= 5; i++)
{
for (int j = 1; j <= 5; j++)
{
p[i, j] = sum;
richTextBox1.Text += p[i, j].ToString();
sum++;
}
}
int C;
int R=1;
for (int i = 1; i <= 5; i++)
{
C = i;
for (int r = 1; r <= i; r++)
{
Output = Output + p[r, C];
C--;
}
}
richTextBox2.Text += Output.ToString();
for (int i = 2; i >= 5; i++)
{
R = i;
for (C = 5; C >= i; C--)
{
Output = Output + p[R, C];
R++;
}
}
richTextBox2.Text += Output.ToString();
This is more fiddly than you might think!
You want to traverse the diagonals of this matrix:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
starting at the bottom left and traversing each diagonal as depicted in this very badly-drawn diagram:
I've written a helper method called DiagonalIndices() that for a given maximum index (in the case of your 5x5 matrix, it will be 4) will produce a sequence of (row,col) indices in the correct order to traverse all the diagonals.
Note that the input array MUST be square - I'm assuming that is the case for your data! It clearly is for a 5x5 matrix.
The output of the following program is
21 16 22 11 17 23 6 12 18 24 1 7 13 19 25 2 8 14 20 3 9 15 4 10 5
Here's the code:
using System;
using System.Collections.Generic;
namespace ConsoleApplication4
{
public sealed class Index
{
public Index(int row, int col)
{
Row = row;
Col = col;
}
public readonly int Row;
public readonly int Col;
}
public static class Program
{
private static void Main()
{
int [,] p = new int[5, 5];
for (int i = 0, n = 1; i < 5; ++i)
for (int j = 0; j < 5; ++j, ++n)
p[i, j] = n;
// This is the bit you will use in your program.
// Replace the Console.WriteLine() with your custom code
// that uses p[index.Row, index.Col]
int maxIndex = p.GetUpperBound(1);
foreach (var index in DiagonalIndices(maxIndex))
Console.Write(p[index.Row, index.Col] + " ");
Console.WriteLine();
}
public static IEnumerable<Index> DiagonalIndices(int maxIndex)
{
for (int i = 0; i <= maxIndex; ++i)
for (int j = 0; j <= i; ++j)
yield return new Index(maxIndex-i+j, j);
for (int i = 0; i < maxIndex; ++i)
for (int j = 0; j < maxIndex-i; ++j)
yield return new Index(j, i+j+1);
}
}
}
This is a more efficient of printing only the diagonal values in a positive direction in a matrix.
int [,] p = new int [5,5]
{
{1, 2, 3, 4,5},
{6, 7, 8, 9},
{10,11,12,13},
{14,15,16,17},
{18,19,20,21},
{22,23,24,25}
};
for (int i = 4, j = 4; i >= 0 && j > = 0; i--, j--)
{
Console.Writeline(p[ i, j ]);
}
So I have an object called, for lack of a better word, MatricesMatrix which is a Matrix of Matrices (everything is stored as a double[,]). I want to strip all of the values from the inner matrices into one big Matrix. Here is what I have so far:
public Matrix ConvertToMatrix()
{
//Figure out how big the return matrix should be
int totalRows = this.TotalRows();
int totalColumns = this.TotalColumns();
Matrix returnMatrix = new Matrix(totalRows, totalColumns);
List<object> rowElementsList = new List<object>();
//"outer" index means an index of the MatricesMatrix
//"inner" index means an index of a Matrix within the Matrices Matrix
//outer row loop
for (int outerRowIndex = 0; outerRowIndex < NumberOfRows; outerRowIndex++)
{
//outer column loop
for (int outerColumnIndex = 0; outerColumnIndex < NumberOfColumns; outerColumnIndex++)
{
Matrix currentMatrix = GetElement(outerRowIndex, outerColumnIndex);
object element = null;
//inner row loop
for (int innerRowIndex = 0; innerRowIndex < currentMatrix.NumberOfRows; innerRowIndex++)
{
//inner column loop
for (int innerColumnIndex = 0; innerColumnIndex < currentMatrix.NumberOfColumns; innerColumnIndex++)
{
element = currentMatrix.GetElement(innerRowIndex, innerColumnIndex);
}
}
returnMatrix.SetElement(outerRowIndex, outerColumnIndex, (double)element);
}
}
return returnMatrix;
}
Note that I have determined programmatically the total number of rows and columns the returnMatrix needs to have.
Here are some more guidelines and output cases:
Each element of the big matrix should be in the same position relative to the other elements of the big matrix that came from the Matrix inside of MatricesMatrix that the element came from.
Each "matrix" (no longer in matrix form) inside of the big matrix should be in the same position relative to the other matrices inside of the big matrix as it was inside of the MatricesMatrix (with no overlapping, and 0's in any spaces left empty).
CASE 1
Given this input: a MatricesMatrix(2,2) with [0,0] = (2x2 matrix), [0,1] = (2x3 matrix), [1,0] = (2x2 matrix), and [1,1] = (2x3 matrix). That is,
Output must be:
CASE 2
Given this input: a MatricesMatrix(2,2) with [0,0] = (1x1 matrix), [0,1] = (3x3 matrix), [1,0] = (2x2 matrix), and [1,1] = (4x4 matrix). That is,
Output should be something like:
Any assistance would be greatly appreciated!
UPDATE:
Here is a unit test for Case 1 that should pass:
[TestMethod]
public void MatricesMatrix_ConvertToMatrixTest()
{
Matrix m1 = new Matrix(2);
Matrix m2 = new Matrix(2, 3);
Matrix m3 = new Matrix(2);
Matrix m4 = new Matrix(2, 3);
double[] m1Row1 = { 1, 1 };
double[] m1Row2 = { 1, 1 };
double[] m2Row1 = { 2, 2, 2 };
double[] m2Row2 = { 2, 2, 2 };
double[] m3Row1 = { 3, 3 };
double[] m3Row2 = { 3, 3 };
double[] m4Row1 = { 4, 4, 4 };
double[] m4Row2 = { 4, 4, 4 };
m1.SetRowOfMatrix(0, m1Row1);
m1.SetRowOfMatrix(1, m1Row2);
m2.SetRowOfMatrix(0, m2Row1);
m2.SetRowOfMatrix(1, m2Row2);
m3.SetRowOfMatrix(0, m3Row1);
m3.SetRowOfMatrix(1, m3Row2);
m4.SetRowOfMatrix(0, m4Row1);
m4.SetRowOfMatrix(1, m4Row2);
MatricesMatrix testMatricesMatrix = new MatricesMatrix(2, 2);
testMatricesMatrix.SetElement(0, 0, m1);
testMatricesMatrix.SetElement(0, 1, m2);
testMatricesMatrix.SetElement(1, 0, m3);
testMatricesMatrix.SetElement(1, 1, m4);
Matrix expectedResult = new Matrix(4, 5);
double[] expectedRow1 = { 1, 1, 2, 2, 2 };
double[] expectedRow2 = { 1, 1, 2, 2, 2 };
double[] expectedRow3 = { 3, 3, 4, 4, 4 };
double[] expectedRow4 = { 3, 3, 4, 4, 4 };
expectedResult.SetRowOfMatrix(0, expectedRow1);
expectedResult.SetRowOfMatrix(1, expectedRow2);
expectedResult.SetRowOfMatrix(2, expectedRow3);
expectedResult.SetRowOfMatrix(3, expectedRow4);
Matrix actualResult = testMatricesMatrix.ConvertToMatrix();
(actualResult == expectedResult).Should().BeTrue();
}
I started with a simple Matrix class to hold the double[,]s. Nothing too fancy, just a simple array-of-arrays with a row and column count and array accessor.
class Matrix<T>
{
public int Rows { get; private set; }
public int Cols { get; private set; }
private T[,] mat;
public Matrix(int rowCount, int colCount)
{
Rows = rowCount;
Cols = colCount;
mat = new T[Rows, Cols];
}
public T this[int r, int c]
{
get { return mat[r, c]; }
set { mat[r, c] = value; }
}
}
Your second case looks more difficult (and like a better test of correctness) than the first, so I set up a metamatrix to match that.
public static Matrix<double[,]> BuildMetaMatrix()
{
Matrix<double[,]> m = new Matrix<double[,]>(2, 2);
m[0, 0] = new double[,]
{
{ 1 }
};
m[0, 1] = new double[,]
{
{ 3, 3, 3 },
{ 3, 3, 3 },
{ 3, 3, 3 }
};
m[1, 0] = new double[,]
{
{ 2, 2 },
{ 2, 2 }
};
m[1, 1] = new double[,]
{
{4, 4, 4, 4},
{4, 4, 4, 4},
{4, 4, 4, 4},
{4, 4, 4, 4}
};
return m;
}
For convenience, I made a Place function that puts one matrix into another one at the given location.
static void Place(double[,] src, double[,] dest, int destR, int destC)
{
for (int row = 0; row < src.GetLength(ROW_DIM); row++)
{
for (int col = 0; col < src.GetLength(COL_DIM); col++)
{
dest[row + destR, col + destC] = src[row, col];
}
}
}
The magic numbers fed into GetLength() were just asking for mistakes, so I defined some constants for them (ROW_DIM = 0 and COL_DIM = 1). I decided to handle the padding by figuring out how wide a column is and how tall a row is and skipping any extra elements after Place()ing the sub-matrix in. A GetRowHeight() and GetColWidth() method figure out the values.
public static int GetRowHeight(Matrix<double[,]> m, int row)
{
int maxSeen = 0;
for (int col = 0; col < m.Cols; col++)
{
if (m[row, col].GetLength(ROW_DIM) > maxSeen)
{
maxSeen = m[row, col].GetLength(ROW_DIM);
}
}
return maxSeen;
}
public static int GetColWidth(Matrix<double[,]> m, int col)
{
int maxSeen = 0;
for (int row = 0; row < m.Rows; row++)
{
if (m[row, col].GetLength(COL_DIM) > maxSeen)
{
maxSeen = m[row, col].GetLength(COL_DIM);
}
}
return maxSeen;
}
A Flatten() function loops through all the sub-matrices, Place()ing them at the appropriate row and column in a new matrix. It updates the next row and column after each Place() using the GetRowHeight() and GetColWidth() functions.
Matrix<double> Flatten(Matrix<Matrix<double>> src)
{
// (7, 6) == (this.TotalRows(), this.TotalColumns())
// from your code.
Matrix<double> dest = new Matrix<double>(7, 6);
int nextRow = 0;
int nextCol = 0;
for (int row = 0; row < src.Rows; row++)
{
for (int col = 0; col < src.Rows; col++)
{
dest.Place(src[row, col], nextRow, nextCol);
nextCol += GetColWidth(src, col);
}
nextRow += GetRowHeight(src, row);
nextCol = 0;
}
return dest;
}
A little glue to test it out...
static void Main(string[] args)
{
Matrix<double[,]> src = BuildMetaMatrix();
double[,] dest = Flatten(src);
Print(dest);
Console.ReadLine();
}
static void Print(double[,] matrix)
{
for (int row = 0; row < matrix.GetLength(ROW_DIM); row++)
{
for (int col = 0; col < matrix.GetLength(COL_DIM); col++)
{
Console.Write(matrix[row, col] + "\t");
}
Console.Write("\n");
}
}
...and you get an output just like your second case with all the oddly fitting matrices and 0s in the empty places.*
1 0 3 3 3 0
0 0 3 3 3 0
0 0 3 3 3 0
2 2 4 4 4 4
2 2 4 4 4 4
0 0 4 4 4 4
0 0 4 4 4 4
*The destination matrix gets its values initialized to default(double), which happens to be 0 (the value you wanted). If you need something other than default(double) for the empty places, you can probably get them by iterating over the new matrix and writing the new default value everywhere before Flatten()ing the metamatrix.
(Thanks to Jeff Mercado for pointing out that multidimensional arrays' GetLength() method can be used to find their dimensions.)
I think it would be beneficial to you to break up the solution into the quadrants you are trying to fill. This will all be under the assumption that we will only be combining 4 matrices in this 2x2 configuration. The same strategies explined here can be applied to other dimensions of matrices to be combined.
So given 4 matrices A, B, C and D, we will try to build a resulting matrix in this arrangement:
+---+---+
| A | B |
+---+---+
| C | D |
+---+---+
Before we can start, we will need to figure out the dimensions of the final result. This should hopefully make sense. We'll have a top half, bottom half, left half and right half.
rows_top = max(rows_A, rows_B)
rows_bottom = max(rows_C, rows_D)
rows_result = rows_top + rows_bottom
cols_left = max(cols_A, cols_C)
cols_right = max(cols_B, cols_D)
cols_result = cols_left + cols_right
Then we will want to consider which regions of the result matrix we want to copy each of the 4 matrices. Considering the origin at the top-left, everything on the right half will be shifted over by the size of the left half, everything on the bottom half will be shifted over by the size of the top half. The offsets for each of the matrices would be:
offset_A = (0, 0)
offset_B = (0, cols_left)
offset_C = (rows_top, 0)
offset_D = (rows_top, cols_left)
Now with all this information, we can start building up the result matrix. Just copy over the values from each matrix to the result, with the offsets applied.
So in code, I would do this:
// I'm just going to use plain 2D arrays here
public T[,] Combine<T>(T[,] a, T[,] b, T[,] c, T[,] d)
{
// get the total rows
var rows_top = Math.Max(a.GetLength(0), b.GetLength(0));
var rows_bottom = Math.Max(c.GetLength(0), d.GetLength(0));
var rows_result = rows_top + rows_bottom;
// get the total columns
var cols_left = Math.Max(a.GetLength(1), c.GetLength(1));
var cols_right = Math.Max(b.GetLength(1), d.GetLength(1));
var cols_result = cols_left + cols_right;
// get the offsets
var offset_a = Tuple.Create(0, 0);
var offset_b = Tuple.Create(0, cols_left);
var offset_c = Tuple.Create(rows_top, 0);
var offset_d = Tuple.Create(rows_top, cols_left);
// fill 'er up
var result = new T[rows_result, cols_result];
Fill(result, a, offset_a);
Fill(result, b, offset_b);
Fill(result, c, offset_c);
Fill(result, d, offset_d);
return result;
}
public void Fill<T>(T[,] result, T[,] source, Tuple<int, int> offset)
{
for (var i = 0; i < source.GetLength(0); i++)
for (var j = 0; j < source.GetLength(1); j++)
result[offset.Item1 + i, offset.Item2 + j] = source[i, j];
}
Then to demonstrate the result in terms of case 2:
const string A = "A", B = "B", C = "C", D = "D";
var a = new string[1,1]
{
{ A },
};
var b = new string[3, 3]
{
{ B, B, B },
{ B, B, B },
{ B, B, B },
};
var c = new string[2, 2]
{
{ C, C },
{ C, C },
};
var d = new string[4, 4]
{
{ D, D, D, D },
{ D, D, D, D },
{ D, D, D, D },
{ D, D, D, D },
};
var result = Combine(a, b, c, d);
This of course can be generalized to any size matrix of matrices. The concept is the same in every step of the process.
Given m x n matrices, we will try to build a resulting matrix in this arrangement:
+-----+-----+-----+
| 0,0 | ... | 0,n |
+-----+-----+-----+
| ... | | ... |
+-----+-----+-----+
| m,0 | ... | m,n |
+-----+-----+-----+
Get the dimensions of each of the slices.
rows_0 = max(rows_0_0, ..., rows_0_n)
...
rows_m = max(rows_m_0, ..., rows_m_n)
rows_result = sum(rows_0, ..., rows_m)
cols_0 = max(cols_0_0, ..., cols_m_0)
...
cols_n = max(cols_0_n, ..., cols_m_n)
cols_result = sum(cols_0, ..., cols_m)
Get the offsets for each of the matrices. Each vertical slice is offset to the left by the total amount of columns in the previous vertical slices. Each horizontal slice is offset to the down by the total amount of rows in the previous horizontal slices.
offset_0_0 = (0, 0)
...
offset_m_n = (sum(rows_0, ..., rows_m-1), sum(cols_0, ..., cols_n-1))
So now we can build up the result matrix.
public T[,] Combine<T>(T[,][,] m)
{
// get the rows
var rows = GetSliceRows(m);
var rows_result = rows.Sum();
// get the cols
var cols = GetSliceCols(m);
var cols_result = cols.Sum();
// get the offsets
var offsets = GetOffsets(rows, cols);
// fill 'er up
var result = new T[rows_result, cols_result];
Fill(result, m, offsets);
return result;
}
public int[] GetSliceRows<T>(T[,][,] m)
{
var sliceRows = new int[m.GetLength(0)];
var segments = m.GetLength(1);
for (var i = 0; i < sliceRows.Length; i++)
{
sliceRows[i] = Enumerable.Range(0, segments)
.Select(j => m[i, j].GetLength(0))
.Max();
}
return sliceRows;
}
public int[] GetSliceCols<T>(T[,][,] m)
{
var sliceCols = new int[m.GetLength(1)];
var segments = m.GetLength(0);
for (var j = 0; j < sliceCols.Length; j++)
{
sliceCols[j] = Enumerable.Range(0, segments)
.Select(i => m[i, j].GetLength(1))
.Max();
}
return sliceCols;
}
public Tuple<int, int>[,] GetOffsets(int[] rows, int[] cols)
{
var offsets = new Tuple<int, int>[rows.Length, cols.Length];
for (var i = 0; i < rows.Length; i++)
for (var j = 0; j < cols.Length; j++)
offsets[i, j] = Tuple.Create(
rows.Take(i).Sum(),
cols.Take(j).Sum()
);
return offsets;
}
public void Fill<T>(T[,] result, T[,][,] m, Tuple<int, int>[,] offsets)
{
for (var i = 0; i < m.GetLength(0); i++)
for (var j = 0; j < m.GetLength(1); j++)
Fill(result, m[i, j], offsets[i, j]);
}
public void Fill<T>(T[,] result, T[,] source, Tuple<int, int> offset)
{
for (var i = 0; i < source.GetLength(0); i++)
for (var j = 0; j < source.GetLength(1); j++)
result[offset.Item1 + i, offset.Item2 + j] = source[i, j];
}
I think you have to give array elements corresponding rowid and columnid to achieve the indexing issue of the outer matrix. Assuming you already have a Array to Matrix object conversion;
Being not sure if I undestood the rules correctly, but here is what I implemented so far:
I implemented Matrix and MatrixList classes as follows:
public class Matrix
{
public int row { get; set; }
public int column { get; set; }
public double value { get; set; }
}
public class MatrixList
{
public List<Matrix> matrixList = new List<Matrix>();
}
Using those classes, I implemented the algorithm below:
List<MatrixList> matricesMatrix = new List<MatrixList>();
init(matricesMatrix);
int totalRows = 10;//as you stated, this is already known
int totalColumns = 10;//as you stated, this is already known
List<Matrix> ResultMatrix = new List<Matrix>();
foreach (MatrixList matrixListItem in matricesMatrix)
{
for (int i = 0; i < totalRows; i++)
{
List<Matrix> matrixItemList = matrixListItem.matrixList.FindAll(s => s.row == i);
foreach(Matrix matrixItem in matrixItemList)
for (int j = 0; j < totalColumns; j++)
{
if (matrixItem.column == j)
ResultMatrix.Add(new Matrix { row = i, column = j, value = matrixItem.value });
}
}
}
where init is a method to fill the objects, implemented as follows:
private void init(List<MatrixList> matricesMatrix)
{
MatrixList ml = new MatrixList();
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
ml.matrixList.Add(new Matrix { row = i, column = j, value = i + j });
}
}
matricesMatrix.Add(ml);
}
I was on a windows forms dummy app, so used a richtextbox to test the code above.
for (int i = 0; i < totalRows; i++)
{
foreach (Matrix item in ResultMatrix)
{
if (item.row == i)
{
for (int j = 0; j < totalColumns; j++)
if (item.column == j)
richTextBox1.Text += item.value + " ";
}
}
richTextBox1.Text += Environment.NewLine;
}
and the result is:
0 1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
2 3 4 5 6 7 8 9 10 11
3 4 5 6 7 8 9 10 11 12
4 5 6 7 8 9 10 11 12 13
5 6 7 8 9 10 11 12 13 14
6 7 8 9 10 11 12 13 14 15
7 8 9 10 11 12 13 14 15 16
8 9 10 11 12 13 14 15 16 17
9 10 11 12 13 14 15 16 17 18
I don't have much time to give pretty numbers to array items to show beriefly at the moment, but I think you can get the idea.
So I have a number array like this
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
And know what I want to know is how to make it read the number 7 after the number 3, and number 8 after number 4. And so on, like this:
0 -> 1 -> 2 -> 3
|
\/
4 <- 5 <- 6 <- 7
|
\/
8 -> 9 -> 10 -> 11
|
\/
12 <- 13 <- 14 <- 15
However if I use nested incremental for it will read in normal sequential order.
I have no idea how to make it read from 3 to 7, 4 to 8 and so on...
How can I achieve that?
You can store a flag indicating if the next iteration is going to start on the left or right. So...
static void Main(string[] args)
{
// initializing values
int[,] arr = new int[4, 4];
int n = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
arr[i, j] = n++;
}
}
n = 0;
// initialization end
// starts from the left
bool left = true;
// go line by line
for (int i = 0; i < 4; i++)
{
// if it starts from the left, set start point a index 0
// otherwise start from max index
for (int j = left ? 0 : 3; left ? j < 4 : j >= 0; )
{
arr[i, j] = n++;
// increment/decrements depending on the direction
j = left ? j + 1 : j - 1;
}
// if it started from the left, the next iteration will
// start from the right
left = !left;
}
}
Results:
Initialized:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
After navigating on it:
0 1 2 3
7 6 5 4
8 9 10 11
15 14 13 12
If you have:
_arr = new int[,] { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 }, { 12, 13, 14, 15 } };
Then try:
public void PrintArr()
{
for (int i = 0; i < 4; i++)
{
if (i % 2 == 0)
{
for (int j = 0; j < 4; j++)
Console.Write(_arr[i, j] + " ");
Console.WriteLine();
}
else
{
for (int j = 3; j >= 0; j--)
Console.Write(_arr[i, j] + " ");
Console.WriteLine();
}
}
}
Here's a short, simple solution:
int h = array.GetLength(0), w = array.GetLength(1);
for(int i = 0, j = 0, c = 1; i < h; i++, c = -c, j += c)
{
for(int k = 0; k < w; k++, j += c)
{
Console.WriteLine(array[i, j]);
}
}