Равномерное распределение массивов PHP по столбцам

1

Итак, я хочу распределить равномерные списки по 3 столбцам. Списки не могут быть разбиты или переупорядочены.

На данный момент у меня есть 5 списков, каждый из которых содержит соответственно 4, 4, 6, 3 и 3 позиции.

Мой первоначальный подход:

$lists = [4,4,6,3,3];
$columns = 3;
$total_links = 20;
$items_per_column = ceil($total_links/$columns);
$current_column = 1;
$counter = 0;
$lists_by_column = [];
foreach ($lists as $total_items) {
    $counter += $total_items;
    $lists_by_column[$current_column][] = $total_items;
    if ($counter > $current_column*$links_per_column) {
        $current_column++;
    }
}

Результаты в:

[
    [4],
    [4,6],
    [3,3]
]

Но я хочу, чтобы это выглядело так:

[
    [4,4],
    [6],
    [3,3]
]

Я хочу всегда иметь наименьшее возможное изменение длины между столбцами.

Другие примеры ожидаемых результатов:

[6,4,4,6] => [[6], [4,4], [6]]

[4,4,4,4,6] => [[4,4], [4,4], [6]]

[10,4,4,3,5] => [[10], [4,4], [3,5]]

[2,2,4,6,4,3,3,3] => [[2,2,4], [6,4], [3,3,3]]

  • 1
    Я до сих пор не уверен, чего вы здесь добиваетесь. Что вы подразумеваете под тем, что I want the first column to contain the first 2 lists, the second, the third list and the last must contain the last 2 lists. Другое дело, почему ваш ожидаемый результат 10, 4, 4, 3, 5 отличается от 4, 4, 4, 4, 6 ?
  • 0
    Я нашел эти требования очень неясными ... у них нет четкой картины, и этот вопрос звучит как проблема XY. Что вы действительно пытаетесь сделать с этим дистрибутивом? Там может быть лучшее решение.
Показать ещё 3 комментария
Теги:

2 ответа

1

Примерно то, что вам нужно сделать, это цикл над количеством столбцов в вашем foreach(). Это будет распространять их для вас.

$numrows = ceil(count($lists) / $columns);
$thisrow = 1;
foreach ($lists as $total_items) {
    if($thisrow < $numrows){
        for($i = 1; $i <= $columns; $i++){
            $lists_by_column[$i][] = $total_items;
        }
    }else{
        //this is the last row
        //find out how many columns need to fit.
        //1 column is easy, it goes in the first column
        //2 columns is when you'll need to skip the middle one
        //3 columns is easy because it full
    }
    $thisrow++;
}

Это будет равномерное распределение слева направо. Но на самом деле вы хотите изменить равномерное распределение, которое будет выглядеть симметрично для глаз. Таким образом, в цикле foreach вам нужно будет отслеживать 1.), если вы находитесь в последней строке из трех, и 2.), если есть 2 остатка, чтобы он пропустил col2 и нажал вместо col3. Вам нужно будет настроить это, чтобы иметь возможность поиграть с ним... но вы всего лишь пара логических ворот от земли молока и меда.

  • 0
    Я не понимаю, что вы имеете в виду, if you're on the last row of three
  • 0
    Если в вашем массиве 23 ключа и вы знаете, что вам нужно 3 столбца. Вы знаете, что вам понадобится 8 рядов, чтобы удержать их все ... ceil (23/3). Итак, для первых 7 строк ... все нормально и полно и распределяется равномерно. Вам не нужно ничего делать. В последнем ряду вам нужно будет ввести логику для обработки того, какой столбец идет куда. Я немного дополню свой пример, чтобы вы могли видеть поток.
Показать ещё 1 комментарий
0

Итак, я использовал этот код:

$lists = [4,4,6,3,3];
$columns = 3;
$total_links = 20;
$items_per_column = ceil($total_links/$columns);
$current_column = 1;
$lists_by_column = [];

for ($i = 0; $i < count($lists); $i++) {
    $total = $lists[$i];
    $lists_by_column[$current_column][] = $lists[$i];

    //Loop until reaching the end of the column
    while ($total < $items_per_column && $i+1 < count($lists)) {
        if ($total + $lists[$i+1] > $items_per_column) {
            break;
        }
        $i++;
        $total += $lists[$i];
        $lists_by_column[$current_column][] = $lists[$i];
    }

    //When exiting the loop the last time we need another break
    if (!isset($lists[$i+1])) {break;}

    //If the last item goes onto the next column
    if (abs($total - $items_per_column) < abs($total + $lists[$i+1] - $items_per_column)) {
        $current_column++;
    //If the last item goes onto the current column
    } else if ($total + $lists[$i+1] > $items_per_column) {
        $i++;
        $lists_by_column[$current_column][] = $lists[$i];
        $current_column++; 
    }
}
  • 1
    Пара стилевых вещей может сделать его немного легче для чтения. 1.) Вы можете жестко закодировать $ столбцы, если это никогда не изменится. 2.) если (! Isset ($ lists [$ i + 1])) {break;} не требует скобок вокруг break; И есть пара мест, где вы можете использовать сокращение if. 3.) если count ($ lists) совпадает с $ total_links, вы можете сделать это один раз в верхней части.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню