c# summarise Blocks in a Grid like structure - c#

i am searching for an algorithm that can find the the biggest Areas in a Grid.
if i have something like this:
Red Blocks = Blocks with Collision
i have to check 28 collision Objekts.
I need an algorithm that can find this:
now i only have to check 5 Objekts.
Is there an easy c# algorithm for that?

If you wanted the absolute minimum number of rectangles, then I would suggest this answer to you. Since you want easy, though, here's my suggestion, which is 2-competitive with the minimum. First, by scanning the rows one by one, find the minimum exact cover with rectangles only one row high.
00000000
1 2
3 44 5
6 77 8
99999999
Now for each pair of adjacent rows in turn, try to merge their rectangles. Assuming that they are sorted by horizontal position, then the loop looks like a sorted merge.
00000000
--------
1 2
No merges possible.
1 2
--------
3 44 5
Merge 1, 3 and 2, 5.
1 2
1 44 2
--------
6 77 8
Merge 1, 6 and 4, 7 and 2, 8.
1 2
1 44 2
1 44 2
--------
99999999
No merges possible. The final result is the following.
00000000
1 2
1 44 2
1 44 2
99999999

here is a solution for Unity
using UnityEngine;
using System.Collections;
public class CollisionTileMerger:MonoBehaviour{
ArrayList rects = new ArrayList();
public int[,] rowCheck(int[,]array)
{
int y = array.GetLength(0);
int x = array.Length /y ;
int count = 1;
ArrayList rec = new ArrayList ();
for(int i=0; i< y ;i++){
for(int j=0; j< x ;j++)
{
if(array[i,j] == -1)
{
array[i,j] = count;
rec.Add(i);
rec.Add(j);
}
else
{
if(rec.Count>0)
{
rects.Add (rec);
rec = new ArrayList();
count++;
}
}
}
if(rec.Count>0)
{
rects.Add (rec);
rec = new ArrayList();
count++;
}
}
return array;
}
public int[,] Merger(int[,]array)
{
int y = array.GetLength(0);
int x = array.Length /y ;
int[,] coppy = (int[,])array.Clone ();
for (int i=0; i< y-1; i++)
{
int row = i;
for (int j=0; j< x; j++)
{
if(coppy[row,j]>0&&coppy[row+1,j]>0)
{
if(j==0)
{
coppy[row+1,j] = coppy[row,j];
}
else
{
if((coppy[row,j-1]>0&&coppy[row+1,j-1]>0)||(coppy[row,j-1]==0&&coppy[row+1,j-1]==0))
{
coppy[row+1,j] = coppy[row,j];
if(j==x-1)
{
//letzte Zeile
//speichern
array = (int[,])coppy.Clone ();
}
}
else
{
//zurücksetzen
coppy = (int[,])array.Clone ();
}
}
}
else if(coppy[row,j]==0&&coppy[row+1,j]==0)
{
//speichern
array = (int[,])coppy.Clone ();
}
else
{
//zurücksetzen
coppy = (int[,])array.Clone ();
}
}
}
//speichern
array = (int[,])coppy.Clone ();
return array;
}
// Use this for initialization
void Start () {
int[,] a = new int[,] {
{-1,-1,-1,-1,-1,-1,-1,-1},
{-1, 0, 0, 0, 0, 0, 0,-1},
{-1, 0, 0, -1, 0, 0, 0,-1},
{-1, 0, 0, -1, 0, 0, 0,-1},
{-1, 0, 0, -1, 0, 0, 0,-1},
{-1, 0, 0,-1,-1, 0, 0,-1},
{-1, 0, 0,-1,-1, 0, 0,-1},
{-1, 0, 0,-1,-1, 0, 0,-1},
{-1,-1,-1,-1,-1,-1,-1,-1}};
displayArray (Merger(rowCheck (a)));
}
// Update is called once per frame
void Update () {
}
public void displayArray(int[,]array)
{
int y = array.GetLength(0);
int x = array.Length /y ;
string row="";
for (int i = 0; i< y; i++)
{
for(int j = 0; j<x;j++)
{
row+= array[i,j]+" ";
}
row+= "\r\n";
}
Debug.Log(row);
/*foreach( int a in array )
{
Debug.Log( array.GetLength(0) );
Debug.Log( array.Length );
}*/
}
}

Related

Wrong output of Dijkstra algorithm using C#

I tried to implement dijkstra algorithm in c# but the output is wrong and it can not calculate right distance from source node.
I use an array called distance to update and store shortest path from source node.
Vertex list is declared to save intermediate nodes that construct shortest path.
Here is my code :
namespace Dijkstra
{
public class Program
{
static void Main(string[] args)
{
int[][] graph = {
new int []{ 0, 1, 7, 0, 0 },
new int [] { 0, 0, 4,4, 1},
new int []{ 0, 0, 0, 3, 2 },
new int []{ 0, 0, 0, 0, 5 },
new int []{ 0, 0, 0, 0, 0 } };
ShortestPath(graph, 0);
}
static void ShortestPath(int[][]graph,int source)
{
int nodes = graph.GetLength(0);
int[] distance = new int[nodes];
List<int> vertex = new List<int>();
List<int> edge = new List<int>();
int nearvertex = 0;
int min = int.MaxValue;
for(int i = 0; i< graph.GetLength(0); i++)
{
distance[i] = graph[source][i];
if (distance[i] == 0 && i != source)
distance[i] = int.MaxValue;
}
while(nodes-1 > 0)
{
min = int.MaxValue;
for (int j = 0; j < graph.GetLength(0); j++)
{
if (distance[j] <= min && 0 < distance[j] && !vertex.Contains(j))
{
min = distance[j];
nearvertex = j;
}
}
edge.Add(min);
for (int i = 0; i < graph.GetLength(0); i++)
{
if (distance[nearvertex] + graph[nearvertex][i] < distance[i] &&!vertex.Contains(i))
{
distance[i] = distance[nearvertex] + graph[nearvertex][i];
vertex.Add(nearvertex);
}
}
distance[nearvertex] = -1;
nodes--;
}
foreach(var i in edge)
Console.WriteLine(i);
}
}
}
Is there any problem with comparisons in for loops?
How can i fix it?
There are few things wrong on your code. I'll point them for you.
See below code and comments.
static void ShortestPath(int[][] graph, int source)
{
int nodes = graph.GetLength(0);
int[] distance = new int[nodes];
List<int> vertex = new List<int>();
int nearvertex = 0;
int min = int.MaxValue;
for (int i = 0; i < distance.Length; i++)
{
// Distance array should be initialized to max except source vertex.
distance[i] = int.MaxValue;
}
distance[source] = 0;
while (nodes - 1 > 0)
{
min = int.MaxValue;
for (int j = 0; j < graph.GetLength(0); j++)
{
// 0 < distance[j] --> 0 <= distance[j] : starting point distance is 0, so should be <=
if (distance[j] <= min && 0 <= distance[j] && !vertex.Contains(j))
{
min = distance[j];
nearvertex = j;
}
}
//edge.Add(min); edge array is unnecessary.
for (int i = 0; i < graph.GetLength(0); i++)
{
// you are using 0 as un-reachable distance value in your graph array, so you should check it.
if (distance[nearvertex] + graph[nearvertex][i] < distance[i] && graph[nearvertex][i] > 0 && !vertex.Contains(i))
{
distance[i] = distance[nearvertex] + graph[nearvertex][i];
vertex.Add(nearvertex);
}
}
//distance[nearvertex] = -1; No change required after refreshing distance array.
nodes--;
}
// shortest path from source ( 0 ) will be restored in distance array.
foreach (var i in distance)
Console.WriteLine(i);
}
Sample Result
// 0, 1, 7, 0, 0
// 0, 0, 4, 4, 1
// 0, 0, 0, 3, 2
// 0, 0, 0, 0, 5
// 0, 0, 0, 0, 0
0 // source vertex
1 // 0 -> 1
5 // 0 -> 1 -> 2
5 // 0 -> 1 -> 3
2 // 0 -> 1 -> 4

Loop diagonally in 2D array in c#

I have below 2D array where I need to loop diagonally to find the similar value in adjacent and provide the counter for how many times it has occurred diagonally.
For e.g. below is 2d array
int[,] arrayGroup= new int[,] {
{ 99, 99, 0, 0, 0, 0 },
{ 0, 99, 0, 0, 0, 0 },
{ 99, 0, 99, 0, 0, 0 },
{ 0, 0, 0, 0, 99, 0 },
{ 0, 0, 0, 0, 0, 99 },
{ 99, 99, 0, 99, 0, 0 }
};
so this array should give me output as 99 is present 4 times adjacent diagonally.
For this I am trying below code, but somehow I am not able to get the exact diagonal count
int diagonalCnt = 0;
for (var row = 0; row < arrayGroup.GetLength(0); row++)
{
for (var col = 0; col < arrayGroup.GetLength(1); col++)
{
if (arrayGroup[row, col] == 99 && arrayGroup[row + 1, col + 1] == 99)
{
diagonalCnt = diagonalCnt + 1;
}
}
}
Any help on this appreciated !
Several issues:
You don't need to loop through the entire matrix. Assuming it's square of size N x N, you need to loop N times and check the arrayGroup[i, i] and arrayGroup[i + 1, i + 1] values
You compare the values explicitly to 1. What you want to do it to compare the value to the next value: if (arrayGroup[row, col] == 1 && arrayGroup[row + 1, col + 1] == 1)
Here's the solution:
for(int i = 0; i < N - 1; i++)
{
if(arrayGroup[i, i] == arrayGroup[i + 1, i + 1])
{
diagonalCnt += 1;
}
}
Because you are talking about Diagonal 2D Array, you mean a Square Only Matrix.
So to traverse through the diagonal you will need to loop from 0 to N - 1 because the diagonal will have N elements.
like this:
int max_count = arrayGroup.GetLength(0);
int count = 0;
for(int i = 0; i < max_count; i++)
if(arrayGroup[i, i] == 99)
count++;
Console.WriteLine("Number of 99's is: " + count.ToString());

How to find indices for all contiguous elements in an array that appear more than threshold

I'm trying to find indices for all contiguous elements that occurrence more than Threshold in one dimensional integer array using c#
double[] x = new double[20]{1,1,0,0,0,0,1,1,0,0,0,0,1,1,1,0,0,0,1,1};
I want to get indices for this x[] vector as the following for 0 values
threshold=4
start-index[0] =2
end-index[0] =5
start-index[1] =8
end-index[1] =11
i try to use this code, but there is many problems in it
public void myFunc(double[] x, ref List<int> start, ref List<int> end,int matchingVal,int threshold)
{
int count = 0;
for (int i = 0; i < x.Length; i++)
{
for (int j = i+1; j < threshold; j++)
{
if (x[i] == x[j] && x[i] == matchingVal)
{
count++;
}
else
{
break;//no contiguous element
}
if (count >= threshold)
{
start.Add(i);
end.Add(i + count);
count = 0;
}
else
continue;
}
}
}
If you are willing to use MoreLINQ, consider using GroupAdjacent.
An example is below. Basically, it takes the original array, uses Select to include the index, uses GroupAdjacent to group adjacent values together, uses Where and Count to check there are at least 4 adjacent values, then uses Select to project an anonymous type including the value and its first and last index (this can be changed to project to whatever concrete type you want). Then string.Join is used to write it to the console so you can see the results.
using System;
using System.Linq;
using MoreLinq;
namespace Test
{
class Program
{
static void Main(string[] args)
{
double[] x = new double[20] { 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1 };
var results = x.Select((value, index) => new { value, index })
.GroupAdjacent(z => z.value)
.Where(z => z.Count() >= 4)
.Where(z => z.Key == 0) // it is unclear whether you want to filter for specific values - if so, this is how to do it
.Select(z =>
new { value = z.Key, firstIndex = z.First().index, lastIndex = z.Last().index })
.ToList();
Console.WriteLine(string.Join(Environment.NewLine, results.Select(z => $"{z.value} - {z.firstIndex} - {z.lastIndex}")));
Console.ReadLine();
}
}
}
Updated added more tests and fixed an issue thanks to #AntonínLejsek
Given
public static IEnumerable<(int start, int finish)> GetStuff(int thresh, double[] ary)
{
int start = 0, count = 1;
for (var i = 0; i < ary.Length - 1; i++, count++)
if (ary[i] == ary[i + 1])
{
if (count == 1) start = i;
}
else
{
if (count >= thresh) yield return (start, i);
count = 0;
}
if (count >= thresh) yield return (start, ary.Length-1);
}
Usage
foreach (var tuple in GetStuff(3,ary))
Console.WriteLine($"start : {tuple.start}, finish : {tuple.finish}");
Output
var ary = new double[] { 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1 };
start : 2, finish : 5
start : 8, finish : 11
start : 12, finish : 14
start : 15, finish : 17
var ary = new double[] { 1, 1, 1 ,0 };
start : 0, finish : 2
var ary = new double[] { 1, 1, 1 };
start : 0, finish : 2

Why does every line in the .txt-file output end with 'System.int32'? C#

C#,
Console Application,
Virtual Studio 2015,
Paralelles: Windows 8.1.
The code is as follows:
class txt_program
{
public void txt()
{
/* 0 */
int[] M_array_0 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* 1 */
int[] M_array_1 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* 2 */
int[] M_array_2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
// etc.
// the M matrix
int[][] M = { M_array_0, M_array_1, M_array_2, M_array_3, M_array_4,
M_array_5, M_array_6, M_array_7, M_array_8, M_array_9, M_array_10,
M_array_12, M_array_13 };
// the time pick is beeing called into this item.
Time_pick_2 T2 = new Time_pick_2();
// the if loop making
// 0
if (T2.M_build_0() == true)
{
int nr_0 = 0;
for (int i = nr_0; i < nr_0 + 2; i++)
{
M[1][i] = M_array_0[i] + 1;
}
}
// 1
else if (T2.M_build_1() == true)
{
int nr_1 = 1;
for (int i = nr_1; i < nr_1 + 2; i++)
{
M[1][i] = M_array_1[i] + 1;
}
}
// 2
else if (T2.M_build_2() == true)
{
int nr_2 = 2;
for (int i = nr_2; i < nr_2 + 2; i++)
{
M[2][i] = M_array_2[i] + 1;
}
}
// etc.
using (StreamWriter SW = new StreamWriter(#"txt.txt"))
{
// the loops creating the .txt-file.
for (int i = 0; i < M.GetLength(0); i++)
{
for (int a = 0; a < 13; a++)
{
SW.Write(" " + M[i][a]);
}
SW.WriteLine(M);
}
}
}
}
}
As pastebin:
http://pastebin.com/3HDYwzzZ
The output is given as:
0 0 0 0 0 0 0 0 0 0 0 0 0System.Int32[][]
0 1 1 0 0 0 0 0 0 0 0 0 0System.Int32[][]
0 0 0 0 0 0 0 0 0 0 0 0 0System.Int32[][]
// etc.
I checked some other post about the appearance off System.Int32[][] but in all of the cases it was code that didnot generate any output except System.Int32[], which meant that the code could not interpret the for-loopcreating the output. Here the correct output is displayed but still with the System.Int32[][] end. Why is this and what am I doing wrong?
By default, the ToString method returns the type of the object. So, if you print a non-primitive type without overriding the ToString method (defined in Object class), you will get the type name instead.
The problem line in your case is:
SW.WriteLine(M);
You are outputting the whole array after your inner loop. If you want a newline you could use Console.WriteLine("")
using (StreamWriter SW = new StreamWriter(#"txt.txt"))
{
// the loops creating the .txt-file.
for (int i = 0; i < M.GetLength(0); i++)
{
for (int a = 0; a < 13; a++)
{
SW.Write(" " + M[i][a]);
}
//SW.WriteLine(M); // <-- this line was generating your output
SW.WriteLine("");
}
}
As Heinzbeinz already said you are printing an array which in C# wil result in printing the object type for example:
int[] ar1 = {0,1,2,3};
int[] ar2 = {0,1,2,3};
int[][] m = {ar1,ar2};
Console.WriteLine(m);
wil result in printing System.Int32[][]

Converting a 2D Array of 2D Arrays into a single 2D Array

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.

Categories