Algorithm to evenly distribute items into 3 columns

Tag: algorithm Author: zcaileen Date: 2009-07-22

I'm looking for an algorithm that will evenly distribute 1 to many items into three columns. No column can have more than one more item than any other column. I typed up an example of what I'm looking for below. Adding up Col1,Col2, and Col3 should equal ItemCount.

Edit: Also, the items are alpha-numeric and must be ordered within the column. The last item in the column has to be less than the first item in the next column.

Items         Col1,Col2,Col3
A             A
AB            A,B
ABC           A,B,C
ABCD          AB,C,D
ABCDE         AB,CD,E
@Brian: Please take some time to post the correct question first time. Seven people put significant effort into answering the first version of your question, and now it's changed so that most of that work was wasted.
Could the distribution for ABCD be A|BC|D or A|B|CD ?

Best Answer

Here you go, in Python:

NumCols = 3

for ItemCount in range(1, 12):
    subdata = DATA[:ItemCount]

    Col1Count = (ItemCount + NumCols - 1) / NumCols
    Col2Count = (ItemCount + NumCols - 2) / NumCols
    Col3Count = (ItemCount + NumCols - 3) / NumCols

    Col1 = subdata[:Col1Count]
    Col2 = subdata[Col1Count:Col1Count+Col2Count]
    Col3 = subdata[Col1Count+Col2Count:]

    print "%2d   %5s  %5s  %5s" % (ItemCount, Col1, Col2, Col3)

# Prints:
#  1       A              
#  2       A      B       
#  3       A      B      C
#  4      AB      C      D
#  5      AB     CD      E
#  6      AB     CD     EF
#  7     ABC     DE     FG
#  8     ABC    DEF     GH
#  9     ABC    DEF    GHI
# 10    ABCD    EFG    HIJ
# 11    ABCD   EFGH    IJK


Sorry for not getting the question clear the first time. I think your answer does the trick. I can first sort the items using any algorithm, and then use yours to figure out how many items should be in each column. Again sorry for not being clear on the question.
@Brian: No problem. Now updated to answer your updated question.

Other Answer1

This answer is now obsolete because the OP decided to simply change the question after I answered it. I’m just too lazy to delete it.

function getColumnItemCount(int items, int column) {
    return (int) (items / 3) + (((items % 3) >= (column + 1)) ? 1 : 0);


This was useful once I figured out that "column" is expected to be counted from 0, as opposed to the ordinal column number. :D
Most of these answers don't work when you are dealing with a small amount of content. Try the approved solution with 5 values and you will end up with only two columns! This one seems to work reliably no matter what you throw at it - if you genericised it to pass in the 3 as a column count variable then it would be perfect for any use case (:

Other Answer2

just to give you a hint (it's pretty easy, so figure out yourself)

divide ItemCount by 3, rounding down. This is what is at least in every column.

Now you do ItemCount % 3 (modulo), which is either 1 or 2 (because else it would be dividable by 3, right) and you distribute that.

Other Answer3

It's quite simple

If you have N elements indexed from 0 to N-1 and column indexed from 0to 2, the i-th element will go in column i mod 3 (where mod is the modulo operator, % in C,C++ and some other languages)


After reading your response I thought, "huh that was easy why didn't I think of that." and then I realized there was more to the question. See the edit.

Other Answer4

I needed a C# version so here's what I came up with (the algorithm is from Richie's answer):

// Start with 11 values
var data = "ABCDEFGHIJK";

// Split in 3 columns
var columnCount = 3;

// Find out how many values to display in each column
var columnCounts = new int[columnCount];
for (int i = 0; i < columnCount; i++)
    columnCounts[i] = (data.Count() + columnCount - (i + 1)) / columnCount;

// Allocate each value to the appropriate column
int iData = 0;
for (int i = 0; i < columnCount; i++)
for (int j = 0; j < columnCounts[i]; j++)
    Console.WriteLine("{0} -> Column {1}", data[iData++], i + 1);

//    A -> Column 1
//    B -> Column 1
//    C -> Column 1
//    D -> Column 1
//    E -> Column 2
//    F -> Column 2
//    G -> Column 2
//    H -> Column 2
//    I -> Column 3
//    J -> Column 3
//    K -> Column 3

Other Answer5

Do you just want the count of items in each column? If you have n items, then the counts will be:

round(n/3), round(n/3), n-2*round(n/3)

where "round" round to the nearest integer (e.g. round(x)=(int)(x+0.5))

If you want to actually put the items there, try something like this Python-style pseudocode:

def columnize(items):
  answer=[ [], [], [] ]
  for it in items:
    answer[i%3] += it
    i += 1
  return answer


Your first line of code distributes 10 as (3,3,4), and 11 as (4,4,3).
You're right, it does. These numbers sum up correctly, though. The solution matches the requirements as I read them: no column has more than one more item than any other column. If you want the values to reflect the counts you'd get from the second code block, then I think you can use RichieHindle's code above.
Fair enough - the spec has changed since then anyway.

Other Answer6

This question was the closest thing to my own that I found, so I'll post the solution I came up with. In JavaScript:

var items = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K']
var columns = [[], [], []]
for (var i=0; i<items.length; i++) {
  columns[Math.floor(i * columns.length / items.length)].push(items[i])

Other Answer7

Here's a PHP version I hacked together for all the PHP hacks out there like me (yup, guilt by association!)

function column_item_count($items, $column, $maxcolumns) {
    return round($items / $maxcolumns) + (($items % $maxcolumns) >= $column ? 1 : 0);

And you can call it like this...

$cnt = sizeof($an_array_of_data);
$col1_cnt = column_item_count($cnt,1,3);
$col2_cnt = column_item_count($cnt,2,3);
$col3_cnt = column_item_count($cnt,3,3);

Credit for this should go to @Bombe who provided it in Java (?) above.

NB: This function expects you to pass in an ordinal column number, i.e. first col = 1, second col = 2, etc...