Algorithm for calculating variable column widths for set table width

后端 未结 3 1667
渐次进展
渐次进展 2021-01-02 10:16

I need to figure out an algorithm that will calculate the optimized size of the column widths given the following:

  • the width of the table is fixed to the size
3条回答
  •  情深已故
    2021-01-02 10:52

    An easy solution is to assign attributes to your colums; for example your Notes columns could be flexible. Then you could calculate the maximum width of each column over all rows, set that width for all non-flexible columns and then distribute the remaining space evenly (or possibly weighted by their max width) to the flexible columns.

    But you could also try to find out the attributes with some simple conditions:

    • a column can be word-wrapped if any of its entries has spaces in it. In your example, the dates and possibly the status and type entries cannot be wrapped. The name shouldn't be wrapped under normal circumstances but could be wrapped, if the name is long or if more than one name is given. The notes column should be wrapped.
    • a column should be flexible if its maximum width exceeds, say, the width a cell would have if all sizes were evenly distributed.

    Then go about as described above: Calculate all non-flexible columns width. Check if there is enough space; if not, make the wrappable columns flexible, too. Then calculate the width of the flexible cells, weighted by their maximum widths.

    A possible pseudocode algorithm is below. It makes liberal use of various heuristics, so you should probably take it with a grain of salt. You can adjust these conditions according to your use case, but it will be difficult to cater for all possible cases.

    function layout(table[], width, gutter, col[])
    
        var maxw[col.length]        # max. text width over all rows
        var maxl[col.length]        # max. width of longest word
        var flex[col.length]        # is column flexible?
        var wrap[col.length]        # can column be wrapped?
        var colw[col.length]        # final width of columns
    
        foreach row in table:
            for i = 0 to col.length:
                cell = row[i]
                maxw[i] = max(maxw[i], textwidth(cell))
                if cell.find(" "):
                    maxl[i] = max(maxl[i], wordwidth(cell))
    
        var left = width - (col.length - 1) * gutter
        var avg = left / col.length
        var nflex = 0
    
        # determine whether columns should be flexible and assign
        # width of non-flexible cells
    
        for i = 0 to col.length:
            flex[i] = (maxw[i] > 2 * avg)       # ???
            if flex[i]:
                nflex++
            else:
                colw[i] = maxw[i]
                left -= colw[i]
    
        # if there is not enough space, make columns that could
        # be word-wrapped flexible, too
    
        if left < nflex * avg:
            for i = 0 to col.length:
                if !flex[i] and wrap[i]:
                    left += width[i]
                    colw[i] = 0
                    flex[i] = true
                    nflex += 1
    
        # Calculate weights for flexible columns. The max width
        # is capped at the page width to treat columns that have to 
        # be wrapped more or less equal
    
        var tot = 0
        for i = 0 to col.length:
            if flex[i]:
                maxw[i] = min(maxw[i], width)      # ???
                tot += maxw[i]
    
        # Now assign the actual width for flexible columns. Make
        # sure that it is at least as long as the longest word length
    
        for i = 0 to col.length:
            if flex[i]:
                colw[i] = left * maxw[i] / tot
                colw[i] = max(colw[i], maxl[i])
                left -= colw[i]
    
        return colw
    

提交回复
热议问题