I have a bunch of tables, and some of those table columns are very narrow. I’m trying to write a function that takes one table width info, and arrange them so that the minimum width would be something that I specify. The column widths that I get are adding up to `1.0`

, so the whole table width should also be `1.0`

at the end.

These are some of the values that I’m getting:

[7.231920199501247e-2, 0.9276807980049875], [1.4456630109670987e-2, 0.985543369890329], [ 1.568627450980392e-2, 0.6823529411764706, 0.10196078431372549, 2.3529411764705882e-2, 4.7058823529411764e-2, 7.058823529411765e-2, 5.8823529411764705e-2 ], [ 5.394190871369295e-2, 0.1037344398340249, 5.8091286307053944e-2, 0.23236514522821577, 5.394190871369295e-2, 6.639004149377593e-2, 9.54356846473029e-2, 0.17012448132780084, 0.13278008298755187, 3.319502074688797e-2 ]

Some examples:

- If the minimum column width is
`0.1`

and column widths are`[0.8, 0.05, 0.05, 0.05, 0.05]`

, the output should be`[0.6, 0.1, 0.1, 0.1, 0.1]`

- If the minimum column width is
`0.1`

(10 percent) and the table has 10 columns, all columns should be`0.1`

. - If the minimum column width is
`0.1`

(10 percent) and the table has 11 columns, I shouldn’t change the column widths because that would make the table 110%.

This is the function that I was able to write so far, but sometimes the output exceeds `1.0`

.

def fix_column_widths(column_widths): # If column count multiplied by minimum column width is bigger than 100 percent, leave it. if(MIN_COL_WIDTH * len(column_widths) > 1.0): return column_widths resized_amount = 0.0 if(columns_need_resize(column_widths)): # Start resizing up the small columns to minimum column width for i in range(len(column_widths)): # If column column width is smaller than minimum column width, make it minimum width and store how much it was resized if(column_widths[i] < MIN_COL_WIDTH): resized_amount += MIN_COL_WIDTH - column_widths[i] column_widths[i] = MIN_COL_WIDTH # Calculate the total width of the columns that were not resized. This will be used for deciding how much will be needed to reduce from non resized columns. non_resized_amount = calculate_non_resized_amount(column_widths) # This is probably the place that I need to make changes # Start resizing down the columns that won't be smaller than the miminum column width after resizing for i in range(len(column_widths)): # If (colum width - resize amount) is bigger than minimum column width, resize the column down relatively to other non resized columns if(column_widths[i] - resized_amount * (column_widths[i] / non_resized_amount) > MIN_COL_WIDTH): column_widths[i] = column_widths[i] - resized_amount * (column_widths[i] / non_resized_amount) return column_widths def columns_need_resize(column_widths): for column_width in column_widths: if(column_width < MIN_COL_WIDTH): return True return False def calculate_non_resized_amount(column_widths): non_resized_amount = 0.0 for column_width in column_widths: if(column_width > MIN_COL_WIDTH): non_resized_amount += column_width return non_resized_amount

What I have here, does not work for this array, it should add up to `1.0`

, but I get more than `1.0`

.

[ 5.394190871369295e-2, 0.1037344398340249, 5.8091286307053944e-2, 0.23236514522821577, 5.394190871369295e-2, 6.639004149377593e-2, 9.54356846473029e-2, 0.17012448132780084, 0.13278008298755187, 3.319502074688797e-2 ]

How can I improve this function to have it perfectly resize the small columns without exceeding `1.0`

?

## Answer

I would use numpy, as it makes the array operations a bit easier. My proposal is:

import numpy as np def fix_column_widths(column_widths, minVal = 0.1): # Check error and trivial cases if len(column_widths) * minVal > 1: raise ValueError('Number of elements and min value do not match.') elif len(column_widths) * minVal == 1: return np.ones(len(column_widths)) * minVal # create numpy array from list col = np.array(column_widths) # find values to fix toFix = np.where(col < minVal) # check if there is anything to do if toFix[0].size == 0: return col # find the values we have to renormalize good = np.where(col >= minVal) # calc renormalization factor fixSum = col[toFix].sum() fixDelta = (toFix[0].size * minVal) - fixSum goodSum = 1- fixSum normalization = (goodSum - fixDelta) / goodSum # fix values col[good] = col[good] *normalization col[toFix] = minVal # are there new values after normalization which needs to be fixed? if np.where(col[good] < minVal)[0].size > 0: # do so: recursive call with sub array col[good] = fix_column_widths(col[good], minVal) return col

This function behaves like this:

in [0.0723192 0.9276808] out [0.1 0.9] in [0.01445663 0.98554337] out [0.1 0.9] in [0.05394191 0.10373444 0.05809129 0.23236515 0.05394191 0.06639004 0.09543568 0.17012448 0.13278008 0.03319502] out [0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1] in [0.01568627 0.68235294 0.10196078 0.02352941 0.04705882 0.07058824 0.05882353] out [0.1 0.41871658 0.1 0.1 0.1 0.1 0.1]