2

The setup

I have a List<Room>() which I get back from a service. The list refreshes every 10 seconds, and rooms get added and removed.

class Room 
{
    public int ID {get;set;}
}

My job

To display these rooms on the screen, I have a Matrix-like view of variable size. Sometimes the matrix is 3 x 3 cells, other times it is 4 x 2 or 5 x 1.

I needed a way to "remember" which slot/cell a room has been placed in, so I thought a DataTable would give me that option.

To store the cells I use a DataTable, which has 3 Columns:

  • "Column" (int)
  • "Row" (int)
  • "Room" (Room)

So If I have a 2 x 4 matrix, it would look like this.


 Column  |  Row  |  Room
-----------------------------
    0    |   0   |  rooms[0] 
-----------------------------
    1    |   0   |  rooms[1] 
-----------------------------
    2    |   0   |  rooms[2] 
-----------------------------
    0    |   1   |  rooms[3] 
-----------------------------
    1    |   2   |  rooms[4] 

And so forth...

Once I have this DataTable I am then able to refresh the screen, knowing that each room will be displayed at the position it was before. This can probably be achieved in a smarter way.

The problem

Now I need to enumerate the List<Room> and fill the matrix/DataTable.

If I have more rooms than cells, then I need to start at position 0,0 again (like adding a new matrix as a layer), until all rooms have been assigned a cell.

The approach so far

I have tried a few for(...) loops that look like:

int totalTiles = area.TileColumns * area.TileRows;
int totalLayers = (int)Math.Ceiling((double)area.Rooms.Count / totalTiles);

for (int i = 0; i < totalLayers; i++)
{
    for (int j = 0; j < area.TileRows; j++)
    {
        for (int k = 0; k < area.TileColumns; k++)
        {
            // This is going nowhere :-(
        }
    }
}

In my brain

When I first came across this problem, I immediately thought: "Nothing a simple LINQ query won't fix!". And then I bricked ...

What would be the most efficient / best performing approach to fill this matrix?

Fred Fickleberry III
  • 2,439
  • 4
  • 34
  • 50
  • 1
    but **in my brain**: *LINQ can't always do the things, especially anything related to setting/changing not getting/querying* – King King Aug 20 '13 at 14:04
  • 2
    You shouldn't be using a `DataTable` to represent a matrix. First, it's a fairly "heavy" object, not a lightweight one. Next, it is designed to represent a series of rows, which isn't quite the same as an nxm matrix. One major consequence of that is that you don't set really individual cells, you set rows. You're probably better off with just a multidimensional matrix. – Servy Aug 20 '13 at 14:06

1 Answers1

1

Without being able to make assumptions, like will the row/columns change at runtime, I would have to say just make it completely dynamic.

class RoomStorage
{
    public Room room {get;set;}
    public int layer {get;set;}
    public int row {get;set;}
    public int col {get;set;}
}

var matrix=new List<RoomStorage>();

Then you can things like:

var newRooms=new List<Room>(); // Get from service

//Remove rooms no longer in use
var matrix=matrix.Where(m=>newRooms.Select(nr=>nr.ID).Contains(m.Room.ID));

//Find rooms we need to add (Optionally use Exclude for faster perf)
var roomsToAdd=newRooms.Where(r=>matrix.Select(m=>m.Room.ID).Contains(r.ID));

var maxLayer=matrix.Max(m=>m.layer);
var rows = ?
var cols = ?

var positions=Enumerable
    .Range(0,maxLayer+1)
    .SelectMany(layer=>
        Enumerable
        .Range(0,rows)
        .SelectMany(row=>
            Enumerable
                .Range(0,cols)
                .Select(col=>new {layer,row,col})));

Then you can use positions, left joining it to matrix for display purposes, or finding the first empty position.

Robert McKee
  • 21,305
  • 1
  • 43
  • 57