# Algorithm for adjusting table widths to not have columns smaller than a specified minimum width

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`?

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.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.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).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]
```