Skip to main content
deleted 383 characters in body; edited title
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Array 2D Pairwise Functionpairwise function

    public static IEnumerable<TOut> Pairwise<TIn, TOut>(this TIn[,] source ,Func<TIn, TIn, TOut> 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 < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                Point[] neighbors =
                    deltas
                        .Select(point => new Point(point.X + x, point.Y + y))
                        .Where(point => !(point.X < 0 || point.X >= width || point.Y < 0 || 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 columns, and diagonals, the. The columns and rows were easy, but getting the diagonals was a challenge. 

This is what I came up with  :

 public static IEnumerable<IEnumerable<T>> Diagonals<T>(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 < width + height - 1; ++slice)
        //{
        //    var curSlice = new List<T>();
        //    int z1 = slice < height ? 0 : slice - height + 1;
        //    int z2 = slice < width ? 0 : slice - width + 1;
        //    for (int j = slice - z2; j >= z1; --j)
        //    {
        //        curSlice.Add(source[j, slice - j]);
        //    }
        //    yield return curSlice;
        //}

        List<Tuple<Point, T>> curSlice = new List<Tuple<Point, T>>();

        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<Tuple<Point, T>> prevSlice = curSlice;
            curSlice = new List<Tuple<Point, T>>();
            bool isFirst = true;
            foreach (Point ele in prevSlice.Select(tuple => tuple.Item1))
            {
                int? newY = ele.Y + 1 >= height ? (int?) null : ele.Y + 1 ;
                int? newX = !inverse
                    ? (ele.X + 1 >= width ? (int?) null : ele.X + 1)
                    : (ele.X - 1 < 0 ? (int?) null : ele.X - 1);

                if (isFirst)
                {
                    if (newX != null)
                        curSlice.Add(Tuple.Create(new Point(newX.Value, ele.Y), source[newX.Value, ele.Y]));
                    isFirst = false;
                }

                if (newY != null)
                    curSlice.Add(Tuple.Create(new Point(ele.X, newY.Value), source[ele.X, newY.Value]));
            
            }
            yield return curSlice.Select(tuple => tuple.Item2);

        }


    }

Finally, this was my solution. Is this the simplest solution or did I over-complicate things?

    public static IEnumerable<TOut> Pairwise2<TIn, TOut>(this TIn[,] source, Func<TIn, TIn, TOut> selector)
    {

        int width = source.GetLength(0);
        int height = source.GetLength(1);

        var horizontalSeq = Enumerable.Range(0, width).Pairwise(Tuple.Create).ToArray();
        var verticalSeq = Enumerable.Range(0, height).Pairwise(Tuple.Create).ToArray();


        for (int y = 0; y < height; y++)
        {
            int y1 = y;
            foreach (var e in horizontalSeq.Select(tuple => selector(source[tuple.Item1, y1], source[tuple.Item2, y1])))
                yield return e;
        }



        for (int x = 0; x < width; x++)
        {
            int x1 = x;
            foreach (var e in verticalSeq.Select(tuple => selector(source[x1, tuple.Item1], source[x1, tuple.Item2])))
                yield return e;
        }



        foreach (var e in source.Diagonals().SelectMany(ins => ins.Pairwise(selector)))
        {
            yield return e;
        }


        foreach (var e in source.Diagonals(inverse: true).SelectMany(ins => ins.Pairwise(selector)))
        {
            yield return e;
        }


    }

EDIT:

Example

for this array :

00 03 06 09

01 04 07 10Example for this array:

02 05 08 11

00 03 06 09

01 04 07 10

02 05 08 11

theThe pairs would be  :

(0, 3) (3, 6) (6, 9) (1, 4) (4, 7) (7, 10) (2, 5) (5, 8) (8, 11) (0, 1) (1, 2) (3, 4) (4, 5) (6, 7) (7, 8) (9, 10) (10, 11) (3, 1) (6, 4) (4, 2) (9, 7) (7, 5) (10, 8) (6, 10) (3, 7) (7, 11) (0, 4) (4, 8) (1, 5)

(0, 3) (3, 6) (6, 9) (1, 4) (4, 7) (7, 10) (2, 5) (5, 8) (8, 11) (0, 1) (1, 2) 
(3, 4) (4, 5) (6, 7) (7, 8) (9, 10) (10, 11) (3, 1) (6, 4) (4, 2) (9, 7) (7, 5) (10, 8) 
(6, 10) (3, 7) (7, 11) (0, 4) (4, 8) (1, 5)

Array 2D Pairwise Function

    public static IEnumerable<TOut> Pairwise<TIn, TOut>(this TIn[,] source ,Func<TIn, TIn, TOut> 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 < width; x++)
        {
            for (int y = 0; y < height; y++)
            {
                Point[] neighbors =
                    deltas
                        .Select(point => new Point(point.X + x, point.Y + y))
                        .Where(point => !(point.X < 0 || point.X >= width || point.Y < 0 || 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, diagonals, the columns and rows were easy, but getting the diagonals was a challenge. This is what I came up with  :

 public static IEnumerable<IEnumerable<T>> Diagonals<T>(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 < width + height - 1; ++slice)
        //{
        //    var curSlice = new List<T>();
        //    int z1 = slice < height ? 0 : slice - height + 1;
        //    int z2 = slice < width ? 0 : slice - width + 1;
        //    for (int j = slice - z2; j >= z1; --j)
        //    {
        //        curSlice.Add(source[j, slice - j]);
        //    }
        //    yield return curSlice;
        //}

        List<Tuple<Point, T>> curSlice = new List<Tuple<Point, T>>();

        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<Tuple<Point, T>> prevSlice = curSlice;
            curSlice = new List<Tuple<Point, T>>();
            bool isFirst = true;
            foreach (Point ele in prevSlice.Select(tuple => tuple.Item1))
            {
                int? newY = ele.Y + 1 >= height ? (int?) null : ele.Y + 1 ;
                int? newX = !inverse
                    ? (ele.X + 1 >= width ? (int?) null : ele.X + 1)
                    : (ele.X - 1 < 0 ? (int?) null : ele.X - 1);

                if (isFirst)
                {
                    if (newX != null)
                        curSlice.Add(Tuple.Create(new Point(newX.Value, ele.Y), source[newX.Value, ele.Y]));
                    isFirst = false;
                }

                if (newY != null)
                    curSlice.Add(Tuple.Create(new Point(ele.X, newY.Value), source[ele.X, newY.Value]));
            
            }
            yield return curSlice.Select(tuple => tuple.Item2);

        }


    }

Finally this was my solution. Is this the simplest solution or did I over-complicate things?

    public static IEnumerable<TOut> Pairwise2<TIn, TOut>(this TIn[,] source, Func<TIn, TIn, TOut> selector)
    {

        int width = source.GetLength(0);
        int height = source.GetLength(1);

        var horizontalSeq = Enumerable.Range(0, width).Pairwise(Tuple.Create).ToArray();
        var verticalSeq = Enumerable.Range(0, height).Pairwise(Tuple.Create).ToArray();


        for (int y = 0; y < height; y++)
        {
            int y1 = y;
            foreach (var e in horizontalSeq.Select(tuple => selector(source[tuple.Item1, y1], source[tuple.Item2, y1])))
                yield return e;
        }



        for (int x = 0; x < width; x++)
        {
            int x1 = x;
            foreach (var e in verticalSeq.Select(tuple => selector(source[x1, tuple.Item1], source[x1, tuple.Item2])))
                yield return e;
        }



        foreach (var e in source.Diagonals().SelectMany(ins => ins.Pairwise(selector)))
        {
            yield return e;
        }


        foreach (var e in source.Diagonals(inverse: true).SelectMany(ins => ins.Pairwise(selector)))
        {
            yield return e;
        }


    }

EDIT:

Example

for this array :

00 03 06 09

01 04 07 10

02 05 08 11

the pairs would be  :

(0, 3) (3, 6) (6, 9) (1, 4) (4, 7) (7, 10) (2, 5) (5, 8) (8, 11) (0, 1) (1, 2) (3, 4) (4, 5) (6, 7) (7, 8) (9, 10) (10, 11) (3, 1) (6, 4) (4, 2) (9, 7) (7, 5) (10, 8) (6, 10) (3, 7) (7, 11) (0, 4) (4, 8) (1, 5)

Array 2D pairwise function

public static IEnumerable<TOut> Pairwise<TIn, TOut>(this TIn[,] source ,Func<TIn, TIn, TOut> 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 < width; x++)
    {
        for (int y = 0; y < height; y++)
        {
            Point[] neighbors =
                deltas
                    .Select(point => new Point(point.X + x, point.Y + y))
                    .Where(point => !(point.X < 0 || point.X >= width || point.Y < 0 || 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<IEnumerable<T>> Diagonals<T>(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 < width + height - 1; ++slice)
    //{
    //    var curSlice = new List<T>();
    //    int z1 = slice < height ? 0 : slice - height + 1;
    //    int z2 = slice < width ? 0 : slice - width + 1;
    //    for (int j = slice - z2; j >= z1; --j)
    //    {
    //        curSlice.Add(source[j, slice - j]);
    //    }
    //    yield return curSlice;
    //}

    List<Tuple<Point, T>> curSlice = new List<Tuple<Point, T>>();

    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<Tuple<Point, T>> prevSlice = curSlice;
        curSlice = new List<Tuple<Point, T>>();
        bool isFirst = true;
        foreach (Point ele in prevSlice.Select(tuple => tuple.Item1))
        {
            int? newY = ele.Y + 1 >= height ? (int?) null : ele.Y + 1 ;
            int? newX = !inverse
                ? (ele.X + 1 >= width ? (int?) null : ele.X + 1)
                : (ele.X - 1 < 0 ? (int?) null : ele.X - 1);

            if (isFirst)
            {
                if (newX != null)
                    curSlice.Add(Tuple.Create(new Point(newX.Value, ele.Y), source[newX.Value, ele.Y]));
                isFirst = false;
            }

            if (newY != null)
                curSlice.Add(Tuple.Create(new Point(ele.X, newY.Value), source[ele.X, newY.Value]));
        
        }
        yield return curSlice.Select(tuple => tuple.Item2);

    }


}

Finally, this was my solution. Is this the simplest solution or did I over-complicate things?

public static IEnumerable<TOut> Pairwise2<TIn, TOut>(this TIn[,] source, Func<TIn, TIn, TOut> selector)
{

    int width = source.GetLength(0);
    int height = source.GetLength(1);

    var horizontalSeq = Enumerable.Range(0, width).Pairwise(Tuple.Create).ToArray();
    var verticalSeq = Enumerable.Range(0, height).Pairwise(Tuple.Create).ToArray();


    for (int y = 0; y < height; y++)
    {
        int y1 = y;
        foreach (var e in horizontalSeq.Select(tuple => selector(source[tuple.Item1, y1], source[tuple.Item2, y1])))
            yield return e;
    }



    for (int x = 0; x < width; x++)
    {
        int x1 = x;
        foreach (var e in verticalSeq.Select(tuple => selector(source[x1, tuple.Item1], source[x1, tuple.Item2])))
            yield return e;
    }



    foreach (var e in source.Diagonals().SelectMany(ins => ins.Pairwise(selector)))
    {
        yield return e;
    }


    foreach (var e in source.Diagonals(inverse: true).SelectMany(ins => ins.Pairwise(selector)))
    {
        yield return e;
    }


}

Example for this array:

00 03 06 09

01 04 07 10

02 05 08 11

The pairs would be:

(0, 3) (3, 6) (6, 9) (1, 4) (4, 7) (7, 10) (2, 5) (5, 8) (8, 11) (0, 1) (1, 2) 
(3, 4) (4, 5) (6, 7) (7, 8) (9, 10) (10, 11) (3, 1) (6, 4) (4, 2) (9, 7) (7, 5) (10, 8) 
(6, 10) (3, 7) (7, 11) (0, 4) (4, 8) (1, 5)
added 151 characters in body
Source Link
elios264
  • 367
  • 1
  • 9
 public static IEnumerable<IEnumerable<T>> Diagonals<T>(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 < width + height - 1; ++slice)
        //{
        //    var curSlice = new List<T>();
        //    int z1 = slice < height ? 0 : slice - height + 1;
        //    int z2 = slice < width ? 0 : slice - width + 1;
        //    for (int j = slice - z2; j >= z1; --j)
        //    {
        //        curSlice.Add(source[j, slice - j]);
        //    }
        //    yield return curSlice;
        //}

        List<Tuple<Point, T>> curSlice = new List<Tuple<Point, T>>();

        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<Tuple<Point, T>> prevSlice = curSlice;
            curSlice = new List<Tuple<Point, T>>();
            bool isFirst = true;
            foreach (Point ele in prevSlice.Select(tuple => tuple.Item1))
            {
                int? newY = ele.Y + 1 >= height ? (int?) null : ele.Y + 1 ;
                int? newX = !inverse
                    ? (ele.X + 1 >= width ? (int?) null : ele.X + 1)
                    : (ele.X - 1 < 0 ? (int?) null : ele.X - 1);

                if (isFirst)
                {
                    if (newX != null)
                        curSlice.Add(Tuple.Create(new Point(newX.Value, ele.Y), source[newX.Value, ele.Y]));
                    isFirst = false;
                }

                if (newY != null)
                    curSlice.Add(Tuple.Create(new Point(ele.X, newY.Value), source[ele.X, newY.Value]));
            
            }
            yield return curSlice.Select(tuple => tuple.Item2);

        }


    }

(0, 3) (3, 6) (6, 9) (1, 4) (4, 7) (7, 10) (2, 5) (5, 8) (8, 11) (0, 1) (1, 2) (3, 4) (4, 5) (6, 7) (7, 8) (9, 10) (10, 11) (3, 1) (6, 4) (4, 2) (9, 7) (7, 5) (10, 8) (6, 10) (3, 7) (7, 11) (0, 4) (4, 8) (1, 5)

 public static IEnumerable<IEnumerable<T>> Diagonals<T>(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 < width + height - 1; ++slice)
        //{
        //    var curSlice = new List<T>();
        //    int z1 = slice < height ? 0 : slice - height + 1;
        //    int z2 = slice < width ? 0 : slice - width + 1;
        //    for (int j = slice - z2; j >= z1; --j)
        //    {
        //        curSlice.Add(source[j, slice - j]);
        //    }
        //    yield return curSlice;
        //}

        List<Tuple<Point, T>> curSlice = new List<Tuple<Point, T>>();

        curSlice.Add(Tuple.Create(new Point(0, 0), source[0, 0]));

        while (curSlice.Count > 0)
        {
            
            List<Tuple<Point, T>> prevSlice = curSlice;
            curSlice = new List<Tuple<Point, T>>();
            bool isFirst = true;
            foreach (Point ele in prevSlice.Select(tuple => tuple.Item1))
            {
                int? newY = ele.Y + 1 >= height ? (int?) null : ele.Y + 1 ;
                int? newX = !inverse
                    ? (ele.X + 1 >= width ? (int?) null : ele.X + 1)
                    : (ele.X - 1 < 0 ? (int?) null : ele.X - 1);

                if (isFirst)
                {
                    if (newX != null)
                        curSlice.Add(Tuple.Create(new Point(newX.Value, ele.Y), source[newX.Value, ele.Y]));
                    isFirst = false;
                }

                if (newY != null)
                    curSlice.Add(Tuple.Create(new Point(ele.X, newY.Value), source[ele.X, newY.Value]));
            
            }
            yield return curSlice.Select(tuple => tuple.Item2);

        }


    }

(0, 3) (3, 6) (6, 9) (1, 4) (4, 7) (7, 10) (2, 5) (5, 8) (8, 11) (0, 1) (1, 2) (3, 4) (4, 5) (6, 7) (7, 8) (9, 10) (10, 11) (3, 1) (6, 4) (4, 2) (9, 7) (7, 5) (10, 8)

 public static IEnumerable<IEnumerable<T>> Diagonals<T>(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 < width + height - 1; ++slice)
        //{
        //    var curSlice = new List<T>();
        //    int z1 = slice < height ? 0 : slice - height + 1;
        //    int z2 = slice < width ? 0 : slice - width + 1;
        //    for (int j = slice - z2; j >= z1; --j)
        //    {
        //        curSlice.Add(source[j, slice - j]);
        //    }
        //    yield return curSlice;
        //}

        List<Tuple<Point, T>> curSlice = new List<Tuple<Point, T>>();

        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<Tuple<Point, T>> prevSlice = curSlice;
            curSlice = new List<Tuple<Point, T>>();
            bool isFirst = true;
            foreach (Point ele in prevSlice.Select(tuple => tuple.Item1))
            {
                int? newY = ele.Y + 1 >= height ? (int?) null : ele.Y + 1 ;
                int? newX = !inverse
                    ? (ele.X + 1 >= width ? (int?) null : ele.X + 1)
                    : (ele.X - 1 < 0 ? (int?) null : ele.X - 1);

                if (isFirst)
                {
                    if (newX != null)
                        curSlice.Add(Tuple.Create(new Point(newX.Value, ele.Y), source[newX.Value, ele.Y]));
                    isFirst = false;
                }

                if (newY != null)
                    curSlice.Add(Tuple.Create(new Point(ele.X, newY.Value), source[ele.X, newY.Value]));
            
            }
            yield return curSlice.Select(tuple => tuple.Item2);

        }


    }

(0, 3) (3, 6) (6, 9) (1, 4) (4, 7) (7, 10) (2, 5) (5, 8) (8, 11) (0, 1) (1, 2) (3, 4) (4, 5) (6, 7) (7, 8) (9, 10) (10, 11) (3, 1) (6, 4) (4, 2) (9, 7) (7, 5) (10, 8) (6, 10) (3, 7) (7, 11) (0, 4) (4, 8) (1, 5)

added an example
Source Link
elios264
  • 367
  • 1
  • 9

EDIT:

Example

for this array :

00 03 06 09

01 04 07 10

02 05 08 11

the pairs would be :

(0, 3) (3, 6) (6, 9) (1, 4) (4, 7) (7, 10) (2, 5) (5, 8) (8, 11) (0, 1) (1, 2) (3, 4) (4, 5) (6, 7) (7, 8) (9, 10) (10, 11) (3, 1) (6, 4) (4, 2) (9, 7) (7, 5) (10, 8)

EDIT:

Example

for this array :

00 03 06 09

01 04 07 10

02 05 08 11

the pairs would be :

(0, 3) (3, 6) (6, 9) (1, 4) (4, 7) (7, 10) (2, 5) (5, 8) (8, 11) (0, 1) (1, 2) (3, 4) (4, 5) (6, 7) (7, 8) (9, 10) (10, 11) (3, 1) (6, 4) (4, 2) (9, 7) (7, 5) (10, 8)

added 6 characters in body
Source Link
RubberDuck
  • 31.2k
  • 6
  • 74
  • 177
Loading
Source Link
elios264
  • 367
  • 1
  • 9
Loading