开发者

Most elegant way to get the array element by position?

I have an array:

private int[,] _blocks = new int[6, 4];

It represents a set of blocks which is 6 deep horizontally and 4 deep vertically. Graphically it looks like this:

alt text http://www.angryhacker.com/toys/array.png

I need a function that would take in a number, from 1 to 24 and return the array element that matches. So for number 14, I'd get back _blocks[1, 2];

I've created a simplistic function:

private int GetBlockByPosition(int position)
{
    int count = 0;
    for (int i = 0; i < 6; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            if (++count == position)
                return 开发者_运维技巧_blocks[i, j];
        }
    }
    return -1;
}    

But this seems very wasteful and smells bad. Is there a more elegant and faster way?


Both in the horizontal direction and the vertical direction, you can see a pattern in your table of numbers. You can determine the horizontal position with position / 6 and a vertical position with position % 6 -- the modulo operation.

private int GetBlockByPosition(int position)
{
    return _blocks[((position + 6) / 6) - 1, position % 6];
}

This makes mathematical sense. Division increases in chunks, and modulo (remainder on division) increases one by one. The math is pretty simple.


I'm not sure I follow, but why can't you just calculate he indexes based on the position? Something like this:

return _blocks[((position - 1) % 6),((position + 5) / 6) - 1];


I think you can do like this :

private int GetBlockByPosition(int position)
{
    return _blocks[(position - 1 ) % 6 , (position - 1) / 6];
}


Are the numbers in your array ACTUALLY 1, 2, 3, ... or are you just using them as an example?

If there isn't any pattern to the data in your array that can be taken advantage of, then it looks like the simplistic option may be your best bet.

Or you could always make a one-time pass of the entire structure and build a hash table to be used in subsequent calls...


Depending on your definition of elegant, the following is perhaps a more functional way of solving the problem:

class Program
{
    static void Main(string[] args)
    {
        var blocks = new int[,] {{1,2,3,4,5,6},{7,8,9,10,11,12},{13,14,15,16,17,18},{19,20,21,22,23,24}};
        var position = blocks.FirstPositionOf(14);
        Console.WriteLine(position.X + "," + position.Y + " has the element " + blocks[position.X,position.Y]);
    }

}

class PositionTuple
{
    public int X {get; set;}
    public int Y {get; set;}
}

static class ArrayExtensions
{
    public static IEnumerable<int> AsEnumerable(this int[,] someTwoDimensionalArray)
    {
        foreach (var num in someTwoDimensionalArray)
            yield return num;
    }

    public static PositionTuple FirstPositionOf(this int[,] someTwoDimensionalArray, int someNumber)
    {
        return someTwoDimensionalArray
            .AsEnumerable()
            .Select((num, index) => new { Number = num, Tuple = new PositionTuple { X = index / (someTwoDimensionalArray.GetUpperBound(1) + 1), Y = index % (someTwoDimensionalArray.GetUpperBound(1)+1) }})
            .Where(pair => pair.Number == someNumber)
            .Select(pair => pair.Tuple)
            .First();
    }
}


I would make a more flexible function that can be used elsewhere if you need to

public static T Get2DArrayValueByPosition<T> (T[,] arr, int position)
{
    // Gets the size of the array in first dimention
    step  = arr.GetUpperBound(0) + 1;

    return arr[(position / step ), position % step];
}


Comprehensive solution considering the corner cases:

private int GetBlockByPosition(int position)
{
    if(position % 6 == 0) { // last cells in each row. 6 gives [0,5]
        return _blocks[(position / 6) - 1, (position - 1) % 6];
    } else { // 11 gives [1,4]
        return _blocks[position / 6 , (position % 6) - 1];
    }
}


int result = GetByPosition(_blocks, 14);

private int GetByPosition(int[,] array, int position)
{
    return GetByPositionBaseZero(array, position - 1);
}

private int GetByPositionBaseZero(int[,] array, int position)
{
    int width = array.GetLength(0);
    return array[position % width, position / width];
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜