English 中文(简体)
How to output multicolumn html without "widows"?
原标题:

I need to output to HTML a list of categorized links in exactly three columns of text. They must be displayed similar to columns in a newspaper or magazine. So, for example, if there are 20 lines total the first and second columns would contain 7 lines and the last column would contain 6. The list must be dynamic; it will be regularly changed.

The tricky part is that the links are categorized with a title and this title cannot be a "widow". If you have a page layout background you ll know that this means the titles cannot be displayed at the bottom of the column -- they must have at least one link underneath them, otherwise they should bump to the next column (I know, technically it should be two lines if I were actually doing page layout, but in this case one is acceptable). I m having a difficult time figuring out how to get this done.

Here s an example of what I mean:

Shopping     Link 3      Link1
Link 1       Link 4      Link2
Link 2                   Link 3
Link 3       Cars
             Link 1      Music
Games        Link 2      Link 1
Link 1              
Link 2       News

As you can see, the "News" title is at the bottom of the middle column, and so is a "widow". This is unacceptable. I could bump it to the next column, but that would create an unnecessarily large amount of white space at the bottom of the second column. Instead, the entire list needs to be re-balanced.

I m wondering if anyone has any tips for how to accomplish this, or perhaps source code or a plug in. Python is preferable, but any language is fine. I m just trying to get the general concept down.

最佳回答

The general gist is to build a master list of all "flowable" items (including categories), then go through the list, adjusting rows per column as needed such that no categories remain widowed (or whatever other conditions you may have.)

Module Module1

    Dim Categories As New Dictionary(Of String, List(Of String))

    Sub Main()

        Const Columns As Integer = 3

          create the category items
        Dim ShoppingList As New List(Of String)
        Dim GamesList As New List(Of String)
        Dim CarsList As New List(Of String)
        Dim NewsList As New List(Of String)
        Dim MusicList As New List(Of String)

        ShoppingList.Add("Link1")
        ShoppingList.Add("Link2")
        ShoppingList.Add("Link3")

        GamesList.Add("Link1")
        GamesList.Add("Link2")
        GamesList.Add("Link3")
        GamesList.Add("Link4")

        CarsList.Add("Link1")
        CarsList.Add("Link2")

        NewsList.Add("Link1")
        NewsList.Add("Link2")
        NewsList.Add("Link3")

        MusicList.Add("Link1")

          create the categories
        Categories.Add("Shopping", ShoppingList)
        Categories.Add("Games", GamesList)
        Categories.Add("Cars", CarsList)
        Categories.Add("News", NewsList)
        Categories.Add("Music", MusicList)

          count each category and its items
        Dim TotalRows As Integer = Categories.Count
        For Each kvp As KeyValuePair(Of String, List(Of String)) In Categories
            TotalRows += kvp.Value.Count
        Next

          add a space between each category
        TotalRows += (Categories.Count - 1)

          determine the number of rows per column
        Dim RowsPerColumn As Integer = Int(TotalRows / Columns) + If((TotalRows Mod Columns) > 0, 1, 0)

          build a master list
        Dim master As New List(Of String)
        For Each kvp As KeyValuePair(Of String, List(Of String)) In Categories
            master.Add(kvp.Key)
            For Each item As String In kvp.Value
                master.Add(item)
            Next
            master.Add(" ")
        Next

          remove the last invalid blank item
        master.RemoveAt(master.Count - 1)

          ensure that the RowsPerColumn th-item in the list is not a category
        Dim adjusted As Boolean
        Do
            adjusted = False
            For i As Integer = 1 To master.Count - 1 Step RowsPerColumn - 1
                If Categories.Keys.Contains(master(i)) Then
                    RowsPerColumn += 1   adjust rows per column (could go up or down)
                    adjusted = True
                End If
            Next
        Loop While adjusted

          output resulting table
        Using sw As New IO.StreamWriter("test.htm")
            sw.WriteLine("<html>")
            sw.WriteLine("<body>")
            sw.WriteLine("<table cellspacing=""0"" cellpadding=""3"" border=""1"">")
            For j As Integer = 0 To RowsPerColumn - 1
                sw.WriteLine("<tr>")
                Dim columnCount As Integer = 0   columns written
                For i As Integer = j To master.Count - 1 Step RowsPerColumn
                    sw.WriteLine("<td>" & master(i) & "</td>")
                    columnCount += 1
                Next
                  if the number of columns actually written was less than Columns constant
                If columnCount < Columns Then
                    For c As Integer = 0 To Columns - columnCount - 1
                        sw.WriteLine("<td>&nbsp;</td>")
                    Next
                End If
                sw.WriteLine("</tr>")
            Next
            sw.WriteLine("</table>")
            sw.WriteLine("</body>")
            sw.WriteLine("</html>")
        End Using

    End Sub

End Module
问题回答

暂无回答




相关问题
How to add/merge several Big O s into one

If I have an algorithm which is comprised of (let s say) three sub-algorithms, all with different O() characteristics, e.g.: algorithm A: O(n) algorithm B: O(log(n)) algorithm C: O(n log(n)) How do ...

Grokking Timsort

There s a (relatively) new sort on the block called Timsort. It s been used as Python s list.sort, and is now going to be the new Array.sort in Java 7. There s some documentation and a tiny Wikipedia ...

Manually implementing high performance algorithms in .NET

As a learning experience I recently tried implementing Quicksort with 3 way partitioning in C#. Apart from needing to add an extra range check on the left/right variables before the recursive call, ...

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

Enumerating All Minimal Directed Cycles Of A Directed Graph

I have a directed graph and my problem is to enumerate all the minimal (cycles that cannot be constructed as the union of other cycles) directed cycles of this graph. This is different from what the ...

Quick padding of a string in Delphi

I was trying to speed up a certain routine in an application, and my profiler, AQTime, identified one method in particular as a bottleneck. The method has been with us for years, and is part of a "...

热门标签