Skip to content

Instantly share code, notes, and snippets.

@kitgrose
Created January 9, 2014 06:38
Show Gist options
  • Save kitgrose/8330310 to your computer and use it in GitHub Desktop.
Save kitgrose/8330310 to your computer and use it in GitHub Desktop.
Makes n balanced lists of grouped items in PHP, without breaking up any groups in the initial set and while preserving the order of sets. Useful for taking a grouped set of navigation items and presenting them in columns in a navigation menu.
<?php
/*
Makes n balanced lists of sub-lists, without breaking inside any existing lists.
Expects input in the form:
array(
'Section 1' => array(
'Item',
'Item',
...
),
'Section 2' => array(
...
),
...
)
Returns output in the form:
array(
0 => array(
'Section 1' => array(
'Item',
...
),
...
),
1 => array(
'Section 2' => array(
...
),
...
),
...
)
*/
function generateRandomData($maxSections = 20, $maxItems = 20) {
$output = array();
for($i = 0; $i < rand(5, $maxSections); $i++) {
for($j = 0; $j < rand(1, $maxItems); $j++) {
$output['Section '.($i + 1)][] = 'Item '.($j + 1);
}
}
return $output;
}
function balanceList($fullList, $numColumns = 3) {
$totalListHeight = array_sum(array_map('count', $fullList)) + count($fullList); // Number of items plus number of sections to include headings
$idealColumnHeight = $totalListHeight / $numColumns;
$output = array();
// Prime the column arrays so array_map can work
for($i = 0; $i < $numColumns; $i++) {
$output[$i] = array();
}
$currentColumn = 0;
$listHeightRemaining = $totalListHeight;
foreach($fullList as $title => $section) {
$columnHeightWithSection = array_sum(array_map('count', $output[$currentColumn])) + count($section);
if($columnHeightWithSection > $idealColumnHeight && $currentColumn !== $numColumns - 1) {
$overflow = $columnHeightWithSection - $idealColumnHeight;
// If the overflow of inserting this item is less than the overflow that would be caused by letting it carry over, insert it
$expectedOverflowOnRemainingColumns = $listHeightRemaining / ($numColumns - $currentColumn - 1) - $idealColumnHeight;
if($overflow > $expectedOverflowOnRemainingColumns) {
$currentColumn++;
}
}
$output[$currentColumn][$title] = $section;
$listHeightRemaining -= count($section) + 1;
}
return $output;
}
$numColumns = !empty($_REQUEST['cols']) ? intval($_REQUEST['cols']) : rand(3, 5);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<style>
#columns {
display: table;
width: 100%;
}
#columns div {
display: table-cell;
vertical-align: top;
}
h1 {
font-size: 1em;
}
</style>
</head>
<body>
<div id="columns">
<?php
foreach(balanceList(generateRandomData(), $numColumns) as $column) {
?>
<div class="column">
<?php
foreach($column as $title => $section) {
?>
<h1><?php echo $title; ?></h1>
<ul>
<?php
foreach($section as $item) {
?>
<li><?php echo $item; ?></li>
<?php
}
?>
</ul>
<?php
}
?>
</div>
<?php
}
?>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment