Определить требуемые строки/столбцы с учетом числа

У меня есть несколько элементов управления (диаграммы в этом случае), которые были определены во время выполнения. Я хотел бы поместить их в сетку с соответствующим количеством строк и столбцов. Например,

  • 4 элемента = 2 x 2
  • 8 элементов = 4 x 2
  • 9 элементов = 3 x 3
  • 20 предметов = 5 x 4
  • 11 items = 4 x 3 (мне не нужна пустая ячейка)

Извините, у меня нет никакого кода, чтобы показывать мои попытки. Я начал играть с определения, является ли квадратный корень целым числом, если число равномерно делится на 2 и т.д., И я понял, что не знаю, как атаковать эту проблему. Но об этом я и думаю:

  • Если квадратный корень является целым числом, используйте квадратный корень для количества строк и столбцов (там нет проблем)
  • Если нет, убедитесь, что номер четный (добавьте его, если вам нужно - проблем нет)
  • Найдите наивысшие два целых числа, которые производят число. например Если у меня есть 20 элементов управления, сетка должна быть 5 x 4, а не 10 x 2 (не совсем уверен, лучший способ для этого).

Я был бы признателен, если бы кто-то мог указать мне в правильном направлении - или предложить другой алгоритм, если я уйду с базы.

Ответ 1

Идея: если квадратный корень не является целым числом, наденьте его, а затем разделите целое число на это, уменьшите его.

int columns = (int)sqrt(number);
int lines = (int)ceil(number / (float)columns);

Пример: 21 = > columns = 4, lines = 6.

UPDATE: bonus, он также работает, когда sqrt (число) является целым числом. Никакое округление не происходит нигде, и значения верны.

Ответ 2

"Обычный" способ решения этой проблемы заключается в том, что всегда будет N столбцов (реже, всегда N строк). Затем возникает вопрос о количестве элементов, делящихся на N, и количестве строк, которые у вас есть (плюс один, если есть остаток).

Изменение размера сетки приводит к запутанному пользовательскому интерфейсу. Пользователи не поймут, почему размер сетки продолжает меняться. Они не будут действительно удивляться об этом, но они будут смущены, казалось бы, случайными изменениями.

Если вы все еще хотите делать то, что вы говорите, я думаю, вам нужно будет немного лучше определить вашу проблему. Есть ли максимальное количество элементов, которые могут поместиться в сетку? Есть ли максимальное количество столбцов, которые вы разрешите? Например, если вы разрешаете 50 предметов, должны ли они быть в 25 рядах по 2 элемента? 5 рядов по 10 предметов? 10 строк по 5 элементов?

В какой-то момент вам придется либо прокручивать по горизонтали, либо сказать: "максимальное количество столбцов - X". И если вы собираетесь наложить максимальное количество столбцов, вам лучше сказать "всегда будут столбцы X".

Если у вас нет веских оснований для создания сетки переменных размеров, о которой вы просите, вам лучше справиться с исправлением количества столбцов. Он делает для простого простого кода, а не для сложного взлома, и представляет собой гораздо более последовательный интерфейс для ваших пользователей.

Ответ 3

Быстрая проверка решения @jv42 прекрасно работает:

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);
    }

Ответ 4

Спасибо за этот вопрос и ответ!

Вот код, переведенный в Javascript:

cols = Math.floor( Math.sqrt(totalTiles) );
rows = Math.floor(  Math.ceil( totalTiles / cols ) );

Ответ 5

В WPF элемент управления UniformGrid автоматически вычисляет строки и столбцы сетки без определения строк и столбцов. например:

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

Результат = > показать изображения в 3 столбцах и 3 строках

Ответ 6

У меня была эта проблема, но с некоторыми конкретными требованиями;

  • Количество столбцов никогда не может превышать определенное количество
  • Если количество элементов не укладывалось точно в определенное количество столбцов, я хотел получить как можно больше вдов.

Например:

1 2 3
4 5 6

1 2 3
4 5

1 2 3 4
5 6 7

Я придумал эту (PHP) функцию, я уверен, что ее можно улучшить, хотя:

<?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;
}