tags:

views:

181

answers:

8

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

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?

+6  A: 

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];
Miky Dinescu
+9  A: 

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.

Michael Dickens
For `position=5` the correct answer should be `[0,4]` and for `position=6`, answer is `[0,5]`. Your code does not seem to output them, so I guess some tweaking is necessary.
Joy Dutta
Index out of bounds for position = 4
AngryHacker
+2  A: 

Hi, I think you can do like this :

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

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

Shoko
+1  A: 

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();
    }
}
Aaron Erickson
+1  A: 

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];
}
Courtney de Lautour
+1  A: 

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];
    }
}
Joy Dutta
+1  A: 
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];
}