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

How to refactor this groupby alike method but with index?

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

Problem

I have got such 2d jagged array (row is 1st dimension, column is 2nd dimension, bottom to up, left to right)

0   0   b   b   b   c
0   0   h   g   g   c
0   0   h   a   a   c
0   0   f   f   d   d
0   0   i   j   e   e
0   0   i   j   0   0


I would like to get a 2d jagged array summarize the positions of consecutive elements for each row, and ignore all 0 or single elements (assume that things like x x x y x x would not occur, so there won't be 2 blocks of same chars in a row)

the ideal outcome would be

{(b,3,5,2)}  // char, length, rowID, columnID
{(g,2,4,3)}
{(a,2,3,3)}
{(f,2,2,2), (d,2,2,4)}
{(e,2,1,4)}
{}


this is my code, i feel it is not that readable, so I appreciate any suggestion in C# or F# (Linq extension method is welcomed as well)

Tuple[][] GetHorizontalBricks()
    {
        List[]> ret = new List[]>();

        for (int rowID = 0; rowID > rowBricks = new List>();
            var row = myBoard[rowID];

            int recentCount = 1;
            int columnID = 0;
            while (columnID  1 && recent != '0')
                {
                    rowBricks.Add(Tuple.Create(recent, recentCount, rowID, columnID));

                }
                columnID = next;
                recentCount = 1;
            }

            ret.Add(rowBricks.ToArray());
        }
        return ret.ToArray();
    }

Solution

First of all get rid of these tuples. After one week you will forget what each int represents. Define simple struct/class for your brick.

Second thing, small performance suggestion for big row count - explicit initial list size:

... = new List[]>(myBoard.Length);//assuming myBoard is an array


without it, list would be recreated and rewritten every 4 new elements.

Below is mine implementation with linq extensions. Probably it is not faster. I don't know if it is more readable, but at least line count is smaller :)

public struct Brick
{
    public char Symbol { get; set; }
    public int Length { get; set; }
    public int RowID { get; set; }
    public int ColumnID { get; set; }

    public override string ToString()
    {
        return string.Format("{0} {1} {2} {3}", Symbol, Length, RowID, ColumnID);
    }
}

public Brick[][] GetHorizontalBricks(char[][] board)
{
    return
        board
            .Reverse() //bottom up row order
            .Select((row,rowIndex) =>
                row
                    .Select((c,i) => new { c = c, i = i })
                    .GroupBy(symbol => symbol.c) //assumption that we will never see 2 groups of same nonzero character in single row
                    .Where(symbol => symbol.Key != 0 && symbol.Count() > 1)
                    .Select(brick =>
                        new Brick
                        {
                            Symbol = brick.Key,
                            RowID = rowIndex,
                            ColumnID = brick.First().i,
                            Length = brick.Count()
                        })
                    .ToArray()
            )
            .Reverse() //reverse again to show result in form like you provided
            .ToArray();
}


and Console app test:

static void Main(string[] args)
{
    char[][] board = new char[][]
    {
        new char[] { (char)0, (char)0, 'b' ,'b','b','c'},
        new char[] { (char)0, (char)0, 'h' ,'g','g','c'},
        new char[] { (char)0, (char)0, 'h' ,'a','a','c'},
        new char[] { (char)0, (char)0, 'f' ,'f','d','d'},
        new char[] { (char)0, (char)0, 'i' ,'j','e','e'},
        new char[] { (char)0, (char)0, 'i' ,'j',(char)0,(char)0}
    };

    foreach (var row in new Program().GetHorizontalBricks(board))
    {
        Console.WriteLine("Row:");
        foreach (var brick in row)
            Console.WriteLine(brick);
    }

    Console.ReadLine();
}

Code Snippets

... = new List<Tuple<char, int, int, int>[]>(myBoard.Length);//assuming myBoard is an array
public struct Brick
{
    public char Symbol { get; set; }
    public int Length { get; set; }
    public int RowID { get; set; }
    public int ColumnID { get; set; }

    public override string ToString()
    {
        return string.Format("{0} {1} {2} {3}", Symbol, Length, RowID, ColumnID);
    }
}

public Brick[][] GetHorizontalBricks(char[][] board)
{
    return
        board
            .Reverse() //bottom up row order
            .Select((row,rowIndex) =>
                row
                    .Select((c,i) => new { c = c, i = i })
                    .GroupBy(symbol => symbol.c) //assumption that we will never see 2 groups of same nonzero character in single row
                    .Where(symbol => symbol.Key != 0 && symbol.Count() > 1)
                    .Select(brick =>
                        new Brick
                        {
                            Symbol = brick.Key,
                            RowID = rowIndex,
                            ColumnID = brick.First().i,
                            Length = brick.Count()
                        })
                    .ToArray()
            )
            .Reverse() //reverse again to show result in form like you provided
            .ToArray();
}
static void Main(string[] args)
{
    char[][] board = new char[][]
    {
        new char[] { (char)0, (char)0, 'b' ,'b','b','c'},
        new char[] { (char)0, (char)0, 'h' ,'g','g','c'},
        new char[] { (char)0, (char)0, 'h' ,'a','a','c'},
        new char[] { (char)0, (char)0, 'f' ,'f','d','d'},
        new char[] { (char)0, (char)0, 'i' ,'j','e','e'},
        new char[] { (char)0, (char)0, 'i' ,'j',(char)0,(char)0}
    };

    foreach (var row in new Program().GetHorizontalBricks(board))
    {
        Console.WriteLine("Row:");
        foreach (var brick in row)
            Console.WriteLine(brick);
    }

    Console.ReadLine();
}

Context

StackExchange Code Review Q#16153, answer score: 2

Revisions (0)

No revisions yet.