Algorithms Question Three Columns - herougo/SoftwareEngineerKnowledgeRepository GitHub Wiki

Input:

hi hello car flame

Output:

| car   hi hello |
| flame          |

Sort words, and print them in 3 columns in the above format.

SPOILERS BELOW

Why this is "hard" (i.e. may take more than an hour).

  • handling empty entries
  • coming up with enumerate_horizontally to reuse iterator code
  • proper printing

A Solution

# writing: 12:06pm - 12:29pm
# debugging: 12:29pm - 12:32pm

def enumerate_horizontally(words, num_words, start_of_each_column, empty_end_words=False):
    for i in range(num_words):
        column = i % NUM_COLUMNS
        offset = i // NUM_COLUMNS
        index = start_of_each_column[column] + offset

        word = words[index]
        yield index, word, column

    if empty_end_words and num_words % NUM_COLUMNS > 0:
        for column in range(num_words % NUM_COLUMNS, NUM_COLUMNS):
            yield -1, '', column

def iter_rows(words, num_words, start_of_each_column, max_word_len_each_column):
    line = ['|']
    for i, word, column in enumerate_horizontally(
        words, num_words, start_of_each_column, empty_end_words=True
    ):
        if column == 0 and i != 0:
            line.append('|')
            yield ' '.join(line)
            line = ['|']

        line.append(word + ' ' * (max_word_len_each_column[column] - len(word)))

    line.append('|')
    yield ' '.join(line)


NUM_COLUMNS = 3

def print_columns(text):
    words = text.split(' ')
    words = list(sorted(words))
    num_words = len(words)

    num_per_column = [
        (NUM_COLUMNS - 1 - i + num_words) // NUM_COLUMNS
        for i in range(NUM_COLUMNS)
    ]
    start_of_each_column = [0] * NUM_COLUMNS
    for i in range(1, NUM_COLUMNS):
        start_of_each_column[i] = start_of_each_column[i-1] + num_per_column[i-1]

    max_word_len_each_column = [0] * NUM_COLUMNS
    for i, word, column in enumerate_horizontally(words, num_words, start_of_each_column):
        max_word_len_each_column[column] = max(
            max_word_len_each_column[column],
            len(word)
        )

    for row in iter_rows(words, num_words, start_of_each_column, max_word_len_each_column):
        print(row)


print_columns('car bat joke cinderella')