HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Array 2D pairwise function

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
arraypairwisefunction

Problem

I found myself in the need of a function to pairwise an array 2D so I created one:

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 (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.