在Scala中以一种优雅的方式在网格中呈现带有List属性(单元格值)的对象(列)列表



在Scala模板中呈现模型对象列表(矩阵)的"最佳"方式是什么?

public class Column extends Model {
    public String columnLabel;
    @OneToMany
    public List cells;
}
public class Cell extends Model {
    public String rowLabel; //index
    public BigDecimal value;
}

对于这个问题,对于所有列对象,cells.size()和rowLabel是一致的。控制器返回一个List[Column]给视图。我已经尝试用一个帮助器将列表转换为数组:

@matrix(list: List[Column]):Array = @{
    var rowCount = list.head.values.size()
    var colCount = list.size()
    var m = Array.ofDim[String](rowCount,colCount)
    for (i <- 0 to rowCount-1) {
        for ( j <- 0 to colCount-1) {
            matrix(i)(j) = list(j).cells(i).value.toString();
        }
    }
    return m;
}

,然后在视图中:

<div>
    @for(i <- 1 to currentPage.getList.head.values.size()) {
        <div class="row">
            @for(j <- 1 to currentPage.getList.size()) {
                <div class="col-md-1">@matrix(currentPage.getList)(i)(j)</div>
             }
        </div>
    }
</div>

,但这当然只是提取矩阵值,而不是列或行标签。

是否有一些Scala数组的优点,可以在列表的列表中使用?效率是重要的,因为数组大小将是近似的。20列x 2000行。或者让控制器显式返回矩阵行,而不是尝试在视图中转换它们,这是更好的方法吗?

使用for-comprehension而不是命使式循环,它们在Scala中更自然。对于你的任务,有很多方法可以做到这一点,其中之一是这样的:

// transform your data to grid, i.e. Map((row,col) -> value). 
// Do this outside the template and pass the result (so that you get the immutable map as a template input)
val toGrid = {
  currentPage.getList.map{ col => col.cells.map(cell => 
    (cell.rowLabel, col.columnLabel, cell.value)
  )}.flatten.map{ case (row, col, value) => ((row,col)->value) }.toMap
}
@rows = @{toGrid.map{ case ((row,col),value) => row }.toSet.toList.sorted}
@columns = @{toGrid.map{ case ((row,col),value) => col }.toSet.toList.sorted}

<div>
@for(row -> rows) {
    <div class="row">
    @for(col -> columns) {
     <div>@toGrid.get(row,col).getOrElse("")</div> //if you might have missing rows/cols
    }
    </div>
}
</div>

更新。如果,由于某种原因,您不能在模板之外拥有Scala类,那么下面的代码应该执行得更好(假设行或列之间没有空白):

@data = @{currentPage.getList}
@triplets = @{data.map{
  col => col.cells.map(cell => (cell.rowLabel,col.columnLabel,cell.value)
)}.flatten
@rows = @{triplets.groupBy(_._1).map{ case (row,cols) => 
          (row, cols.map{ case (row,col,value) => (col,value) })
}}
<div>
@for((row,cols) -> rows.sortBy(_._1)) {
  <div class="row">
  @for((col,value) -> cols.sortBy(_._1)){
    <div>@value</div>
  }
  </div>
}
</div>

最新更新