Skip to content

Commit

Permalink
Resolve #382, rewrite prepareSheetXML to scale linearly (#383)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
mlh758 authored and xuri committed Apr 16, 2019
1 parent a88459d commit 0f9170a
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 11 deletions.
12 changes: 12 additions & 0 deletions cell_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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])
}
}
}
2 changes: 1 addition & 1 deletion rows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
//
Expand Down
29 changes: 19 additions & 10 deletions sheet.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}
}
1 change: 1 addition & 0 deletions styles.go
Original file line number Diff line number Diff line change
Expand Up @@ -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++ {
Expand Down

0 comments on commit 0f9170a

Please sign in to comment.