Multi-column balanced lists

List with balanced columns

List with balanced columns

List with unbalanced columns

List with unbalanced columns

Recently I was working on a project where a client wanted a list of items to be displayed over multiple columns, and requested that the columns be balanced (as balanced as possible). It didn’t take me too long to figure out how to do this for 3 columns, but I knew that there was a more general solution, which did take me a little time to figure out. I am sharing my solution here for my future reference. Perhaps some one else will find it useful too. The solution is in php, though the general algorithm should apply to any language.

The intuition that led me to this solution was to examine unbalanced columns. Let’s look at the case of 5 columns with 56 items, as shown in the figures. It quickly becomes obvious that you need 12 items per column (ceil(56/5)). However, this yields columns of lengths 12, 12, 12, 12 and 8. If you decrease the number of total items to 55, then you have balanced columns of 11. If you increase the number of items to 60, you have balanced columns of 12. Thus, it is possible for the last column to have n-1 items less than the other columns, where n is the number of columns. The preferred output is to have columns of 12, 11, 11, 11, and 11. So what we are doing is shifting over elements from columns 2, 3, and 4 to column 5 (note that we are not messing with the order of the elements). We can always achieve the desired result by simply decreasing the number of items from some of the columns by 1. To determine which columns to decrease, we simply look at the difference in the number of elements per column in the unbalanced solution. In the case of 5 columns with 56 items, the last column would only have 8 items, which is 4 less than 12. So we should start reducing the number of items per column at the 2nd column ((5-4)+1). If we had 57 items total, we would start reducing at the 3rd column ((5-3)+1).

Here is the snippet of code which takes care of figuring this out:

$numCols = 5;
$numItems = 56;
$itemsPerCol = ceil($numItems / $numCols);
$adjustedItemsPerCol=$itemsPerCol;
$blank =$itemsPerCol - ($numItems % $itemsPerCol);
if ($blank!=$itemsPerCol && $blank >0) {
  $adjustedItemsPerCol--;
}

While we are looping over our array of items (or, in my example case, using a while loop), we check to see which column we are on, and if we are on the column where we start to decrease the number of items per column, then we switch $itemsPerCol to $adjustedItemsPerCol.

if ($colNum == ($numCols - $blank)) {
  $itemsPerCol=$adjustedItemsPerCol;
}

Feel free to look at this working example, along with the code for it. I have used the CSS float property to make the divs act like columns, and added some colors to help them stand out.

This entry was posted in (x)html, css, php, wordpress. Bookmark the permalink.

Comments are closed.