在FreeMarker中用独立集合生成表格列的最优实现方案问询
I have two independent Sets, and I want to generate a table structured like this:
ColumnA ColumnB Value1 Value1 Value2 Value2 Value3 Value3 Value4 Value4 Value5 Value6I know I can achieve this using a POJO, where the two Sets are fields (like
aandb) of the POJO, with a template example like this:<table> <tr> <th>ColumnA</th> <th>ColumnB</th> </tr> <#list object as c> <tr> <td>${c.a}</td> <td>${c.b}</td> </tr> </#list> </table>But I want to populate ColumnA and ColumnB using the separate Sets directly. I've passed the data with
data.put("set1", SET1)anddata.put("set2", SET2), but my current template code causes the data to be split into separate rows, which doesn't produce the expected table. What's the optimal way to implement this?
Optimal Solution: Use FreeMarker's ?zip Built-in Function
Since you're working with FreeMarker, the cleanest way to pair elements from your two Sets without wrapping them in a POJO is to leverage the ?zip built-in function. This tool takes two sequences (we'll convert your Sets to sequences first) and pairs their elements into tuples that you can iterate over directly in your template.
Here's the adjusted template code:
<table> <tr> <th>ColumnA</th> <th>ColumnB</th> </tr> <#list set1?sequence?zip(set2?sequence) as pair> <tr> <td>${pair[0]!""}</td> <td>${pair[1]!""}</td> </tr> </#list> </table>
Let me break down the key parts:
set1?sequence/set2?sequence: Converts your unordered Sets into ordered sequences. Important: If the order of elements in your table matters, make sure you're using an ordered Set implementation (likeLinkedHashSetorTreeSet) when passing data to the template.?zip: Pairs elements from the two sequences. For example, ifset1contains[Value1, Value2, Value3, Value4, Value5]andset2contains[Value1, Value2, Value3, Value4, Value6], this creates tuples like(Value1, Value1),(Value2, Value2), etc.${pair[0]!""}/${pair[1]!""}: The!""fallback ensures that if one sequence is shorter than the other, missing elements will show an empty string instead of throwing an error.
Handling Uneven Set Lengths
If one Set is longer than the other, ?zip will stop at the length of the shorter sequence. If you want to include all elements from both Sets (filling empty cells for the shorter one), use this approach:
<table> <tr> <th>ColumnA</th> <th>ColumnB</th> </tr> <#assign maxLength = (set1?sequence?length > set2?sequence?length) ? set1?sequence?length : set2?sequence?length> <#list 0..maxLength-1 as idx> <tr> <td>${set1?sequence[idx]!""}</td> <td>${set2?sequence[idx]!""}</td> </tr> </#list> </table>
This code first calculates the length of the longer sequence, then iterates from 0 to that length, pulling elements by index (with fallback to empty string if the index is out of bounds for one sequence).
Quick Notes
- The
?zipfunction is available in FreeMarker 2.3.21 and above. If you're stuck on an older version, you'll need to either upgrade or pre-process the Sets into a list of pairs in your Java code before passing them to the template. - Always double-check your Set implementation if order matters—standard
HashSetdoesn't preserve insertion order, which could lead to mismatched rows in your table.
内容的提问来源于stack exchange,提问作者27P

