Разделение динамического количества элементов на столбцы

У меня есть динамическое количество элементов, в которых мне нужно разделить на столбцы. Допустим, мне дано это:

array("one", "two", "three", "four", "five", "six", "seven", "eight")

Мне нужно сгенерировать это:

<ul>
  <li>one</li>
  <li>two</li>
  <li>three</li>
  <li>four</li>
</ul>
<ul>
  <li>five</li>
  <li>six</li>
  <li>seven</li>
  <li>eight</li>
</ul>

Вот некоторые правила:

  • если нет предметов, я не хочу ничего выплевывать
  • если есть 16 или менее 16 предметов, id как 4 предмета на <ul>
  • если есть более 16 предметов, я бы хотел, чтобы они были распределены равномерно
  • мне придется переупорядочить элементы в алфавитном порядке. если есть 17 элементов, 17-й элемент должен будет перейти в первый столбец, но все должно быть переупорядочено.

Что у меня есть до сих пор:

function divide( $by, $array ) {
 14     $total = count( $array );
 15     $return = array();
 16     $index=0;
 17     $remainder = $total % $by !== 0;
 18     $perRow = $remainder ?
 19         $total / $by + 1:
 20         $total / $by
 21         ;
 22 
 23     for ( $j = 0; $j<$by; $j++ ) {
 24         //$return[] = array();
 25 
 26         if ( $index == 0 ) {
 27             $slice = array_slice( $array, 0, $perRow );
 28             $index = $perRow;
 29             $return[$j] = $slice;
 30         } else {
 31             $slice = array_slice( $array, $index, $perRow );
 32             $index = $index+$perRow;
 33             $return[$j] = $slice;
 34         }
 35     }
}

Я подаю число, например, разделитель( 4, $arrRef ), число определяет количество столбцов, но мне нужно провести рефакторинг, чтобы он определял количество столбцов.


person Reznor    schedule 08.12.2010    source источник
comment
Интересный вопрос. Я бы рекомендовал вам не принимать ответ сразу, так как ответ на этот вопрос с действительно хорошим ответом может занять некоторое время.   -  person Tatu Ulmanen    schedule 08.12.2010
comment
если есть более 16 предметов, я бы хотел, чтобы они были распределены равномерно? Определите равномерное распределение.   -  person Karl Knechtel    schedule 08.12.2010
comment
Ваши условия не являются самосогласованными в отношении сортировки. Вы хотите, чтобы последовательные элементы были в порядке строк (подразумевается в примере) или в порядке столбцов (подразумевается, если имеется 17 элементов, 17-й элемент должен будет перейти в первый столбец)   -  person Tyler Eaves    schedule 08.12.2010
comment
Как предполагает Карл, я думаю, что нужно больше правил. Например, если есть 100 элементов, сколько должно быть столбцов? 4, 5, 10 и т.д...?   -  person webbiedave    schedule 08.12.2010
comment
Это очень распространенная проблема, и она эффективно разбивается на страницы.   -  person Orbling    schedule 08.12.2010
comment
@Karl Карл, я почти уверен, что он имеет в виду даже количество в столбце. В функцию передается количество столбцов. Единственная отсутствующая информация - это порядок строк или столбцов, как спрашивает Тайлер, существующий код - порядок столбцов.   -  person Orbling    schedule 08.12.2010
comment
Под «равномерным распределением» вы имеете в виду, что ему нужно рассчитать, сколько столбцов нужно, чтобы иметь полные строки? Похоже, ваш главный вопрос заключается в том, как изменить его так, чтобы он определял количество столбцов . Что это обозначает?   -  person Jonah    schedule 08.12.2010


Ответы (4)


Я использовал этот код внутри своего шаблона представления.

<?php
$col = 3;
$projects = array_chunk($projects, ceil(count($projects) / $col));

foreach ($projects as $i => $project_chunk)
{
    echo "<ul class='pcol{$i+1}'>";
    foreach ($project_chunk as $project)
        {
        echo "<li>{$project->name}</li>";
    };
    echo "</ul>";
}; ?>
person cwouter    schedule 20.11.2012

Ваши требования довольно странные/расплывчатые, но я думаю, что это делает то, о чем вы просите.

function columnize( array $set, $maxCols = 4 )
{
  if ( count( $set ) <= 16 )
  {
    return array_chunk( $set, 4 );
  }

  return array_chunk( $set, ceil( count( $set ) / $maxCols ) );
}
person Peter Bailey    schedule 08.12.2010
comment
Хотя я думаю, что это следует делать вне функции, для целей OP может быть хорошей идеей также выполнить сортировку массива внутри функции. - person simshaun; 08.12.2010

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

function columnize($items, $columns = 4, $min_per_column = 4) {

    if(empty($items)) return array();

    $result     = array();
    $count      = count($items);
    $min_count  = $min_per_column * $columns;

    if($count <= $min_count) {
        $columns = ceil($count / $min_per_column);
    } else {    
        $per_column = floor($count / $columns);
        $overflow   = count($items) % $columns;
    }

    for($column = 0; $column < $columns; $column++) {
        if($count <= $min_count) {
            $item_count = $min_per_column;
        } else {
            $item_count = $per_column;
            if($overflow > 0) {
                $item_count++;
                $overflow--;
            }
        }
        $result[$column] = array_slice($items, 0, $item_count);
        $items = array_slice($items, $item_count);
    }

    return $result;
}

Вы можете протестировать его здесь:

http://www.ulmanen.fi/stuff/columnize.php

person Tatu Ulmanen    schedule 08.12.2010

Не проверено:

function divide($by, $list, $order = 'c') {
   if (empty($list)) {
       return array();
   }

   if (count($list) <= 16) {
       $by = 4;
   }

   $columnLists = array();
   for ($cIndex = 0; $cIndex < $by; $cIndex++) {
       $columnLists[$cColumn] = array();
   }

   switch ($order) {
       case 'r':
           foreach ($list as $cEntry) {
               $columnLists[$cColumn][] = $cEntry;
               $cColumn = ($cColumn + 1) % $by;
           }

           break;
       case 'c':
       default:
           $maxColumnHeight = intval(count($list) / $by) + (count($list) % $by > 0 ? 1 : 0);
           for ($cIndex = 0; $cIndex < $by; $cIndex++) {
               $columnLists[$cColumn] = array_slice($list, $cIndex * $maxColumnHeight, $maxColumnHeight);
           }

           break;
   }

   return $columnLists;
}
person Orbling    schedule 08.12.2010