Reputation: 28305
I have previously been using the gem spreadsheet
to generate .xls
spreadsheets as part of a ruby project.
However, this has caused various formatting and compatibility issues - the most recent being that old versions of excel only support up to 256 columns per sheet (column IV
). So, rather than hack around with VB or reformatting the data into multiple sheets, it makes more sense to refactor the code to use a .xlsx
generator instead.
Enter axlsx
.
My generated spreadsheets look something like this:
Header1 | Header2 | Header3 |
-----------------------------
aaa | bbb | ccc
-----------------------------
| ddd | eee
-----------------------------
| fff |
(There are actually more like 300 columns and 500 rows, but you get the idea.)
My old approach to generate this, using the spreadsheet
gem, goes along the lines of:
def initialize
@book = Spreadsheet::Workbook.new
@sheet = book.create_worksheet
@columns = 0
end
def write_column(header, rows)
@sheet[0, @columns] = header
rows.each_with_index do |data, i|
@sheet[i+1, @columns] = data
end
@columns += 1
end
However, this approach is invalid for axlsx
. As the documentation states:
Note: The recommended way to generate cells is via Worksheet#add_row
What is the "right" way to generate spreadsheets such as the above, which clearly "look like" they should be generated by an add_column
method rather than add_row
?
The documented approach is to do something like:
sheet.add_row ['Header1', 'Header2', 'Header3']
sheet.add_row ['aaa', 'bbb', 'ccc']
sheet.add_row [nil, 'ddd', 'eee']
sheet.add_row [nil, 'fff', nil]
...However, this is not great since I'm now unable to directly loop through each column of data.
Another approach could be to initialise a big grid of cells, like:
sheet.add_row ['Header1', 'Header2', 'Header3']
3.times { sheet.add_row [nil, nil, nil] }
And then add my data in a separate step, like:
sheet["A2"] = "aaa"
However, this feels wrong - as it's abusing the way in which sheets get generated.
How would the community advise sheets like this be generated?
Upvotes: 0
Views: 400
Reputation: 2145
If you are receiving columns of data, have you tried placing each column as a row in an intermediate array, transposing it, and loading its rows into the Axlsx spreadsheet?
intermediate = [column1, column2, column3]
sheet.add_row ['Header1', 'Header2', 'Header3']
intermediate.transpose.each do |row|
sheet.add_row row
end
I don't know what the "proper" way would be, but transpose is very useful for these kinds of problems.
That may be memory intensive with large amounts of data btw.
Upvotes: 1