How to refactor this groupby alike method but with index? 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&lt;char, int, int, int&gt;[][] GetHorizontalBricks()
    {
        List&lt;Tuple&lt;char, int, int, int&gt;[]&gt; ret = new List&lt;Tuple&lt;char, int, int, int&gt;[]&gt;();

        for (int rowID = 0; rowID &lt; rowNum; rowID++)
        {
            List&lt;Tuple&lt;char, int, int, int&gt;&gt; rowBricks = new List&lt;Tuple&lt;char, int, int, int&gt;&gt;();
            var row = myBoard[rowID];

            int recentCount = 1;
            int columnID = 0;
            while (columnID &lt; columnNum)
            {
                char recent = row[columnID];
                int next = columnID + 1;
                for (; next &lt; columnNum; next++)
                {
                    if (row[next] == recent)
                    {
                        recentCount++;
                    }
                    else
                    {
                        break;
                    }
                }

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

                }
                columnID = next;
                recentCount = 1;
            }

            ret.Add(rowBricks.ToArray());
        }
        return ret.ToArray();
    }
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&lt;Tuple&lt;char, int, int, int&gt;[]&gt;(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) =&gt;
                row
                    .Select((c,i) =&gt; new { c = c, i = i })
                    .GroupBy(symbol =&gt; symbol.c) //assumption that we will never see 2 groups of same nonzero character in single row
                    .Where(symbol =&gt; symbol.Key != 0 &amp;&amp; symbol.Count() &gt; 1)
                    .Select(brick =&gt;
                        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();
}