Resolve #382, rewrite prepareSheetXML to scale linearly (#383)

* Rewrite prepareSheetXML to scale linearly

We don't need to backfill columns into every row for most purposes
Provided makeContiguousColumns for setting styles where we do
need it for a specific region.

Added a benchmark to monitor progress. For 50,000 rows this went
from about 11 seconds to 1 second. The improvements are more
dramatic as the row/column count increases.

* Assigning that row value was redundant
formula
Michael 6 years ago committed by xuri
parent a88459d5f1
commit 0f9170a03b

@ -82,3 +82,15 @@ func ExampleFile_SetCellFloat() {
fmt.Println(val)
// Output: 3.14
}
func BenchmarkSetCellValue(b *testing.B) {
values := []string{"First", "Second", "Third", "Fourth", "Fifth", "Sixth"}
cols := []string{"A", "B", "C", "D", "E", "F"}
f := NewFile()
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := 0; j < len(values); j++ {
f.SetCellValue("Sheet1", fmt.Sprint(cols[j], i), values[j])
}
}
}

@ -446,7 +446,7 @@ func (f *File) InsertRow(sheet string, row int) error {
return f.adjustHelper(sheet, rows, row, 1)
}
// DuplicateRow inserts a copy of specified row (by it Excel row number) below
// DuplicateRow inserts a copy of specified row (by its Excel row number) below
//
// err := xlsx.DuplicateRow("Sheet1", 2)
//

@ -1072,8 +1072,8 @@ func (f *File) workSheetRelsWriter() {
}
}
// fillSheetData fill missing row and cell XML data to made it continuous from
// first cell [1, 1] to last cell [col, row]
// fillSheetData ensures there are enough rows, and columns in the chosen
// row to accept data. Missing rows are backfilled and given their row number
func prepareSheetXML(xlsx *xlsxWorksheet, col int, row int) {
rowCount := len(xlsx.SheetData.Row)
if rowCount < row {
@ -1082,14 +1082,23 @@ func prepareSheetXML(xlsx *xlsxWorksheet, col int, row int) {
xlsx.SheetData.Row = append(xlsx.SheetData.Row, xlsxRow{R: rowIdx + 1})
}
}
for rowIdx := range xlsx.SheetData.Row {
rowData := &xlsx.SheetData.Row[rowIdx] // take reference
cellCount := len(rowData.C)
if cellCount < col {
for colIdx := cellCount; colIdx < col; colIdx++ {
cellName, _ := CoordinatesToCellName(colIdx+1, rowIdx+1)
rowData.C = append(rowData.C, xlsxC{R: cellName})
}
rowData := &xlsx.SheetData.Row[row-1]
fillColumns(rowData, col, row)
}
func fillColumns(rowData *xlsxRow, col, row int) {
cellCount := len(rowData.C)
if cellCount < col {
for colIdx := cellCount; colIdx < col; colIdx++ {
cellName, _ := CoordinatesToCellName(colIdx+1, row)
rowData.C = append(rowData.C, xlsxC{R: cellName})
}
}
}
func makeContiguousColumns(xlsx *xlsxWorksheet, fromRow, toRow, colCount int) {
for ; fromRow < toRow; fromRow++ {
rowData := &xlsx.SheetData.Row[fromRow-1]
fillColumns(rowData, colCount, fromRow)
}
}

@ -2373,6 +2373,7 @@ func (f *File) SetCellStyle(sheet, hcell, vcell string, styleID int) error {
return err
}
prepareSheetXML(xlsx, vcol, vrow)
makeContiguousColumns(xlsx, hrow, vrow, vcol)
for r := hrowIdx; r <= vrowIdx; r++ {
for k := hcolIdx; k <= vcolIdx; k++ {

Loading…
Cancel
Save