【问题标题】:Elegant way in Scala to render List of objects(columns) with List attribute(cell values) in a grid?在 Scala 中以优雅的方式在网格中呈现具有列表属性(单元格值)的对象列表(列)?
【发布时间】:2014-07-21 15:11:04
【问题描述】:

在 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 数组的优点可以用于 List of Lists?效率很重要,因为数组大小约为。 20 列 x 2000 行。还是让控制器显式返回矩阵行而不是尝试在视图中转换它们是更好的方法?

【问题讨论】:

    标签: arrays scala scala-collections playframework-2.3 scala-2.11


    【解决方案1】:

    使用 for-comprehensions 而不是命令式循环,它们在 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>
    

    【讨论】:

    • 我认为这将为每个列对象提供一组行,而不是使用常见的 rowLabels 呈现矩阵 - 或者更具体地说,是具有每列值的行。
    • 为了获得实际的三元组,我必须将 .map{ case (col, (row,value)) =&gt; (col, row, value)} 添加到 zip 中,但现在遇到了 groupBy 编译错误的问题:constructor cannot be instantiated to expected type; found : (T1, T2, T3) required: List[(String, String, java.math.BigDecimal)]
    • 我现在使用不同的方法对其进行了简化。最好在模板之外完成 toGrid 转换,否则它将被调用的次数与网格中的元素一样多。 (它应该是 val,而不是 def)
    • 这绝对有效,但正如您所说,它在模板中表现不佳,正如预期的那样。关于如何在 Java 中创建 Map((row,col) -> value) 的任何提示?
    • 你不能有 Scala 课吗?
    猜你喜欢
    • 2010-10-30
    • 1970-01-01
    • 2013-09-05
    • 2013-03-05
    • 2015-11-28
    • 1970-01-01
    • 1970-01-01
    • 2020-09-04
    • 2019-11-30
    相关资源
    最近更新 更多