I开发者_开发知识库've got a number of controls (charts in this case) that's determined at runtime. I'd like to put these in a grid with the proper number of rows and columns. For example,
- 4 items = 2 x 2
- 8 items = 4 x 2
- 9 items = 3 x 3
- 20 items = 5 x 4
- 11 items = 4 x 3 (I don't care about an empty cell)
Sorry, I don't really have any code to show my attempts. I started playing with determining if the square root is an integer, if the number is evenly divisible by 2 etc. and realized I'm not sure how to attack this problem. But this is what I'm thinking:
- If the square root is an integer, use the square root for the number of rows and columns (no problems there)
- If not, make sure the number is even (add one if you have to - no problems there)
- Find the highest two integers that produce the number. e.g. If I have 20 controls, the grid should be 5 x 4 and not 10 x 2 (not really sure the best way for this)
I'd appreciate it if someone could point me in the right direction - or suggest a different algorithm if I'm way off base.
Idea: If square root is not integer, floor it, then divide whole number by this, ceil it.
int columns = (int)sqrt(number);
int lines = (int)ceil(number / (float)columns);
Example: 21 => columns = 4, lines = 6.
UPDATE: bonus, it also works when sqrt(number) is integer. No rounding occurs anywhere, and values are correct.
The "usual" way of handling this problem is by saying that there will always be N columns (less often, always N rows). The problem then becomes a matter of taking the number of items, dividing by N, and that's the number of rows you have (plus one if there's a remainder).
Changing the size of the grid makes for a confusing user interface. Users won't understand why the size of the grid keeps changing. They won't really wonder about it, but they'll be confused by the seemingly random changes.
If you still want to do what you're saying, I think you'll need to define your problem a little better. Is there a maximum number of items that can fit on the grid? Is there a maximum number of columns that you'll allow? For example, if you allow 50 items, should they be in 25 rows of 2 items? 5 rows of 10 items? 10 rows of 5 items?
At some point you'll have to either scroll horizontally or say, "maximum number of columns is X". And if you're going to impose that maximum number of columns, then you're better off just saying "There will always be X columns."
Unless there's a compelling reason to do the variable-dimension grid that you ask for, you're way better off just fixing the number of columns. It makes for trivially simple code rather than some complicated hack, and it presents a much more consistent interface to your users.
A quick check of @jv42's solution works nicely:
public struct Grid
{
public int x;
public int y;
public Grid(int xx, int yy)
{
x = xx;
y = yy;
}
}
class Program
{
static void Main(string[] args)
{
Grid g0 = GetGrid(1); Debug.Assert(g0.x == 1 && g0.y == 1);
Grid g1 = GetGrid(4); Debug.Assert(g1.x == 2 && g1.y == 2);
Grid g2 = GetGrid(8); Debug.Assert(g2.x == 2 && g2.y == 4);
Grid g3 = GetGrid(9); Debug.Assert(g3.x == 3 && g3.y == 3);
Grid g4 = GetGrid(20); Debug.Assert(g4.x == 4 && g4.y == 5);
Grid g5 = GetGrid(30); Debug.Assert(g5.x == 5 && g5.y == 6);
Grid g6 = GetGrid(99); Debug.Assert(g6.x == 9 && g6.y == 11);
}
public static Grid GetGrid(int n)
{
int columns = (int)Math.Sqrt(n);
int lines = (int)Math.Ceiling(n / (double)columns);
return new Grid(columns, lines);
}
Thank you for this question and answer!
Here is the code translated into Javascript:
cols = Math.floor( Math.sqrt(totalTiles) );
rows = Math.ceil( totalTiles / cols );
In WPF the control UniformGrid calculate automatically the rows and columns of grid without determine the rows and columns. for example:
<UniformGrid >
<Image Source="Images\Aquarium.jpg" Margin="5"/>
<Image Source="Images\Ascent.jpg" Margin="5" />
<Image Source="Images\Autumn.jpg" Margin="5"/>
<Image Source="Images\Crystal.jpg" Margin="5"/>
<Image Source="Images\DaVinci.jpg" Margin="5"/>
<Image Source="Images\Follow.jpg" Margin="5"/>
<Image Source="Images\Friend.jpg" Margin="5"/>
<Image Source="Images\Aquarium.jpg" Margin="5"/>
</UniformGrid>
Result=> show the images in 3 columns and 3 rows
I had this problem but with some specific requirements;
- The number of columns could never exceed a certain amount
- If the number of items didn't fit exactly into a certain number of columns I wanted the most amount of widows possible.
For example:
1 2 3
4 5 6
1 2 3
4 5
1 2 3 4
5 6 7
I came up with this (PHP) function, I'm sure it can be improved upon though:
<?php
function optimalColCount ($numItems, $maxCols = 4) {
$numCols = $numItems;
if ($numCols > $maxCols and $maxCols === 2) {
$numCols = 2;
}
else if ($numCols > $maxCols) {
$numCols = sqrt($numItems);
if (!is_int($numCols) or $numCols > $maxCols) {
$numCols = -1;
for ($i = $maxCols; $i > 2; $i--) {
if ($numItems % $i === 0) {
$numCols = $i;
break;
}
}
if ($numCols === -1) {
$rests = [];
for ($i = $maxCols; $i > 2; $i--) {
$rests[$i] = $numItems % $i;
}
$numCols = array_search(max($rests), $rests);
}
}
}
return $numCols;
}
精彩评论