module Eco class CSV class Table < ::CSV::Table # @param input [Array, Array, Eco::CSV::Table, ::CSV::Table] # - when `Array` => all `rows` as arrays where first array is the **header** def initialize(input) super(to_rows_array(input)) end # @return [Array<::CSV::Row>] def rows [].tap do |out| self.each {|row| out << row} end end # @return [Integer] total number of rows not including the header def length to_a.length - 1 end # @return [Array] each array is the column header followed by its values def columns to_a.transpose end # Adds a new column at the end # @param header_name [String] header of the new column # @return [Eco::CSV::Table] with a new empty column def add_column(header_name) new_col = Array.new(length).unshift(header_name) columns_to_table(columns.push(new_col)) end # @note it will override columns with same header name # @return [Hash] keys are headers, values are arrays def columns_hash columns.map do |col| [col.first, col[1..-1]] end.to_h end private def columns_to_table(columns_array) data = to_rows_array(columns_array.transpose) self.class.new(data) end def to_rows_array(data) case data when Array return data unless data.length > 0 if data.first.is_a?(::CSV::Row) data elsif data.first.is_a?(Array) headers = data.shift data.map do |arr_row| CSV::Row.new(headers, arr_row) end.compact else raise "Expected data that can be transformed into Array" end when ::CSV::Table to_rows_array(data.to_a) when Hash # hash of columns header as key and column array as value rows_arrays = [a.keys].concat(a.values.first.zip(*a.values[1..-1])) to_rows_array(data.keys) else raise "Input type not supported. Given: #{data.class}" end end end end end