def shrink_to_fit(column_sizes, terminal_width):
    """
    If the total size of all columns exceeds the terminal width, then we need to shrink the
    individual column sizes to fit. In most tables, there are one or two columns that are much
    longer than the other columns. We therefore tailor the shrinking algorithm based on this
    principle. The algorithm is as follows:

    1) Truncate the longest column until either the columns all fit in the terminal width or
       the size of the truncated column is equal to the next longest column.
    2) If the columns fit from truncating we are done.
    3) If the columns do not fit, shrink the now equally sized columns 1 char at a time until the
       width fits or these columns equal size of the next smallest column.
    4) Repeat steps 2 and 3 successively until a fit is found.

    Note that there is the pathological case that the terminal is smaller than a single character
    for all columns. Ignore this for now. The only way to handle it would be to print every column
    on it's own line and truncate them to fit. This may be a useful enhancement to make later.
    """
    total_size = sum(column_sizes)
    if total_size <= terminal_width:
        return column_sizes

    # Put the columns in sorted order (largest to smallest)
    sorted_sizes = sorted(column_sizes, reverse=True)

    # Find the index of each sorted column size in the original list and store it
    # Zero out the value in the original list so that we cover duplicate values, since list.index(val)
    # only finds the first instance.
    indexes = []
    for size in sorted_sizes:
        index = column_sizes.index(size)
        indexes.append(index)
        column_sizes[index] = 0

    # Shrink the sorted columns until they fit the terminal width
    while total_size > terminal_width:
        largest = sorted_sizes[0]
        num_largest_columns = sorted_sizes.count(largest)
        if num_largest_columns != len(sorted_sizes):
            next_largest = sorted_sizes[num_largest_columns]
        else:
            # All columns are the same size, so just shrink each one until they fit
            next_largest = 0

        to_remove = total_size - terminal_width
        gap = largest - next_largest

        if gap * num_largest_columns > to_remove:
            # We can resize in this step and we are done
            to_remove_per_column = to_remove / num_largest_columns
            remainder = to_remove % num_largest_columns
            for i in range(num_largest_columns):
                sorted_sizes[i] = largest - to_remove_per_column
            for i in range(remainder):
                sorted_sizes[i] = sorted_sizes[i] - 1
        else:
            # We need to remove the max number of chars until we get to the next largest size then
            # try again
            for i in range(num_largest_columns):
                sorted_sizes[i] = next_largest

        total_size = sum(sorted_sizes)

    # Put the shrunken column sizes in their proper index locations
    for i in range(len(column_sizes)):
        index = indexes[i]
        column_sizes[index] = sorted_sizes[i]

    return column_sizes