Элегантный способ в Scala отображать список объектов (столбцов) с атрибутом списка (значениями ячеек) в сетке?

Каков «лучший» способ отрисовки списка объектов модели (матрицы) в шаблоне 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 согласованы для всех объектов столбца. Контроллер возвращает список [столбец] в представление. Я попытался преобразовать список в массив с помощью помощника:

@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 столбцов х 2000 строк. Или лучше, чтобы контроллер явно возвращал строки матрицы, а не пытался преобразовать их в представлении?


person geeforce    schedule 21.07.2014    source источник


Ответы (1)


Используйте 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>
person Ashalynd    schedule 21.07.2014
comment
Я думаю, что это даст мне набор строк для каждого объекта столбца, а не визуализирует матрицу с общими rowLabels — или, точнее, строки со значениями из каждого столбца. - person geeforce; 21.07.2014
comment
Чтобы получить фактический триплет, мне пришлось добавить .map{ case (col, (row,value)) => (col, row, value)} в zip, но теперь я столкнулся с проблемой с ошибкой компиляции в groupBy: constructor cannot be instantiated to expected type; found : (T1, T2, T3) required: List[(String, String, java.math.BigDecimal)] - person geeforce; 22.07.2014
comment
Я упростил это сейчас, используя другой подход. Желательно, чтобы преобразование toGrid выполнялось вне шаблона, иначе оно будет вызываться столько раз, сколько элементов в вашей сетке. (И это должно быть val, а не def) - person Ashalynd; 22.07.2014
comment
Это определенно работает, но, как вы говорите, плохо работает в шаблоне, как и ожидалось. Любые подсказки о том, как создать карту ((строка, столбец) -> значение) в Java? - person geeforce; 22.07.2014
comment
Разве у вас нет класса Scala? - person Ashalynd; 22.07.2014
comment
Добавлена ​​версия, когда у вас не может быть класса Scala (с ограничением отсутствия пробелов в строках или столбцах) - person Ashalynd; 22.07.2014