patterncsharpMinor
Array 2D pairwise function
Viewed 0 times
arraypairwisefunction
Problem
I found myself in the need of a function to pairwise an array 2D so I created one:
But, as you can see, this function returns duplicates and its performance is not so good. So, I tried a new approach. Instead of getting the neighbors of each element and returning them, it occurred to me that if I pairwise the rows, columns, and diagonals. The columns and rows were easy, but getting the diagonals was a challenge.
This is what I came up with:
```
public static IEnumerable> Diagonals(this T[,] source, bool inverse = false)
{
int width = source.GetLength(0);
int height = source.GetLength(1);
//this code I found returns the diagonals but not the inverse them so I couldnt use it
//for (int slice = 0; slice ();
// int z1 = slice = z1; --j)
// {
// curSlice.Add(source[j, slice - j]);
// }
// yield return curSlice;
//}
List> curSlice = new List>();
curSlice.Add(!inverse
? Tuple.Create(new Point(0, 0), source[0, 0])
: Tuple.Create(new Point(width - 1, 0), source[width - 1, 0]));
while (curSlice.Count > 0)
{
List> prevSlice = curSlice;
curSlice = new List>();
bool isFirst = true;
public static IEnumerable Pairwise(this TIn[,] source ,Func selector)
{
Point[] deltas =
{
new Point(-1, -1), new Point(0, -1), new Point(1, -1),
new Point(-1, 0), new Point(1, 0),
new Point(-1, 1), new Point(0, 1), new Point(1, 1)
};
int width = source.GetLength(0);
int height = source.GetLength(1);
for (int x = 0; x new Point(point.X + x, point.Y + y))
.Where(point => !(point.X = width || point.Y = height))
.ToArray();
TIn current = source[x, y];
foreach (var element in neighbors.Select(point => selector(current, source[point.X, point.Y])))
{
yield return element;
}
}
}
}But, as you can see, this function returns duplicates and its performance is not so good. So, I tried a new approach. Instead of getting the neighbors of each element and returning them, it occurred to me that if I pairwise the rows, columns, and diagonals. The columns and rows were easy, but getting the diagonals was a challenge.
This is what I came up with:
```
public static IEnumerable> Diagonals(this T[,] source, bool inverse = false)
{
int width = source.GetLength(0);
int height = source.GetLength(1);
//this code I found returns the diagonals but not the inverse them so I couldnt use it
//for (int slice = 0; slice ();
// int z1 = slice = z1; --j)
// {
// curSlice.Add(source[j, slice - j]);
// }
// yield return curSlice;
//}
List> curSlice = new List>();
curSlice.Add(!inverse
? Tuple.Create(new Point(0, 0), source[0, 0])
: Tuple.Create(new Point(width - 1, 0), source[width - 1, 0]));
while (curSlice.Count > 0)
{
List> prevSlice = curSlice;
curSlice = new List>();
bool isFirst = true;
Solution
Let's think about this geometrically.
Since we're treating a pair of neighbours
Now most elements have three neighbours: down, right, and down-right
$$
\begin{pmatrix}
0 & \rightarrow & 3 & \rightarrow & 6 & \rightarrow & 9 \\
\downarrow & \searrow & \downarrow & \searrow & \downarrow & \searrow \\
1 & \rightarrow & 4 & \rightarrow & 7 & \rightarrow & 10 \\
\downarrow & \searrow & \downarrow & \searrow & \downarrow & \searrow \\
2 & & 5 & & 8 & & 11
\end{pmatrix}
$$
We can find those neighbours with the following code:
Now we need the down-left neighbours:
$$
\begin{pmatrix}
0 & & 3 & & 6 & & 9 \\
& \swarrow & & \swarrow & & \swarrow \\
1 & & 4 & & 7 & & 10 \\
& \swarrow & & \swarrow & & \swarrow \\
2 & & 5 & & 8 & & 11
\end{pmatrix}
$$
Handily, we can get down-left neighbours by adding one line
Now we need to get the down-neighbours for the right column, and the right-neighbours for the bottom row
$$
\begin{pmatrix}
0 & & 3 & & 6 & & 9 \\
& & & & & & \downarrow \\
1 & & 4 & & 7 & & 10 \\
& & & & & & \downarrow \\
2 & \rightarrow & 5 & \rightarrow & 8 & \rightarrow & 11
\end{pmatrix}
$$
which gives us our final code:
Since we're treating a pair of neighbours
(x, y) as equivalent to (y, x), we can think of our neighbour-relation as being directed. That is, from up/down we can pick one (let's pick down); similarly for left/right, up-left/down-right, and up-right/down-left.Now most elements have three neighbours: down, right, and down-right
$$
\begin{pmatrix}
0 & \rightarrow & 3 & \rightarrow & 6 & \rightarrow & 9 \\
\downarrow & \searrow & \downarrow & \searrow & \downarrow & \searrow \\
1 & \rightarrow & 4 & \rightarrow & 7 & \rightarrow & 10 \\
\downarrow & \searrow & \downarrow & \searrow & \downarrow & \searrow \\
2 & & 5 & & 8 & & 11
\end{pmatrix}
$$
We can find those neighbours with the following code:
public static IEnumerable Pairwise2(TIn[,] source, Func selector)
{
var lastRow = source.GetLength(0) - 1;
var lastColumn = source.GetLength(1) - 1;
for (var i = 0; i < lastRow; i++)
{
for (var j = 0; j < lastColumn; j++)
{
var current = source[i, j];
yield return selector(current, source[i, j + 1]);
yield return selector(current, source[i + 1, j]);
yield return selector(current, source[i + 1, j + 1]);
}
}
}Now we need the down-left neighbours:
$$
\begin{pmatrix}
0 & & 3 & & 6 & & 9 \\
& \swarrow & & \swarrow & & \swarrow \\
1 & & 4 & & 7 & & 10 \\
& \swarrow & & \swarrow & & \swarrow \\
2 & & 5 & & 8 & & 11
\end{pmatrix}
$$
Handily, we can get down-left neighbours by adding one line
public static IEnumerable Pairwise2(TIn[,] source, Func selector)
{
var lastRow = source.GetLength(0) - 1;
var lastColumn = source.GetLength(1) - 1;
for (var i = 0; i < lastRow; i++)
{
for (var j = 0; j < lastColumn; j++)
{
var current = source[i, j];
yield return selector(current, source[i, j + 1]);
yield return selector(current, source[i + 1, j]);
yield return selector(current, source[i + 1, j + 1]);
yield return selector(source[i, j + 1], source[i + 1, j]);
}
}
}Now we need to get the down-neighbours for the right column, and the right-neighbours for the bottom row
$$
\begin{pmatrix}
0 & & 3 & & 6 & & 9 \\
& & & & & & \downarrow \\
1 & & 4 & & 7 & & 10 \\
& & & & & & \downarrow \\
2 & \rightarrow & 5 & \rightarrow & 8 & \rightarrow & 11
\end{pmatrix}
$$
which gives us our final code:
public static IEnumerable Pairwise2(TIn[,] source, Func selector)
{
var lastRow = source.GetLength(0) - 1;
var lastColumn = source.GetLength(1) - 1;
for (var i = 0; i < lastRow; i++)
{
for (var j = 0; j < lastColumn; j++)
{
var current = source[i, j];
yield return selector(current, source[i, j + 1]);
yield return selector(current, source[i + 1, j]);
yield return selector(current, source[i + 1, j + 1]);
yield return selector(source[i, j + 1], source[i + 1, j]);
}
yield return selector(source[i, lastColumn], source[i + 1, lastColumn]);
}
for (var j = 0; j < lastColumn; j++)
{
yield return selector(source[lastRow, j], source[lastRow, j + 1]);
}
}Code Snippets
public static IEnumerable<TOut> Pairwise2<TIn, TOut>(TIn[,] source, Func<TIn, TIn, TOut> selector)
{
var lastRow = source.GetLength(0) - 1;
var lastColumn = source.GetLength(1) - 1;
for (var i = 0; i < lastRow; i++)
{
for (var j = 0; j < lastColumn; j++)
{
var current = source[i, j];
yield return selector(current, source[i, j + 1]);
yield return selector(current, source[i + 1, j]);
yield return selector(current, source[i + 1, j + 1]);
}
}
}public static IEnumerable<TOut> Pairwise2<TIn, TOut>(TIn[,] source, Func<TIn, TIn, TOut> selector)
{
var lastRow = source.GetLength(0) - 1;
var lastColumn = source.GetLength(1) - 1;
for (var i = 0; i < lastRow; i++)
{
for (var j = 0; j < lastColumn; j++)
{
var current = source[i, j];
yield return selector(current, source[i, j + 1]);
yield return selector(current, source[i + 1, j]);
yield return selector(current, source[i + 1, j + 1]);
yield return selector(source[i, j + 1], source[i + 1, j]);
}
}
}public static IEnumerable<TOut> Pairwise2<TIn, TOut>(TIn[,] source, Func<TIn, TIn, TOut> selector)
{
var lastRow = source.GetLength(0) - 1;
var lastColumn = source.GetLength(1) - 1;
for (var i = 0; i < lastRow; i++)
{
for (var j = 0; j < lastColumn; j++)
{
var current = source[i, j];
yield return selector(current, source[i, j + 1]);
yield return selector(current, source[i + 1, j]);
yield return selector(current, source[i + 1, j + 1]);
yield return selector(source[i, j + 1], source[i + 1, j]);
}
yield return selector(source[i, lastColumn], source[i + 1, lastColumn]);
}
for (var j = 0; j < lastColumn; j++)
{
yield return selector(source[lastRow, j], source[lastRow, j + 1]);
}
}Context
StackExchange Code Review Q#58005, answer score: 5
Revisions (0)
No revisions yet.