class Eco::CSV::Table

Public Class Methods

new(input) click to toggle source

@param input [Array<Row>, Array<Array>, Eco::CSV::Table, ::CSV::Table]

- when `Array<Array>` => all `rows` as arrays where first array is the **header**
Calls superclass method
# File lib/eco/csv/table.rb, line 7
def initialize(input)
  super(to_rows_array(input))
end

Public Instance Methods

add_column(header_name) click to toggle source

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

# File lib/eco/csv/table.rb, line 110
def add_column(header_name)
  new_col = Array.new(length).unshift(header_name)
  columns_to_table(columns.push(new_col))
end
columns() click to toggle source

@return [Array<Array>] each array is the column header followed by its values

# File lib/eco/csv/table.rb, line 151
def columns
  to_a.transpose
end
columns_hash() click to toggle source

Creates a single `Hash` where each key, value is a column (header + values) @note it will override columns with same header name @return [Hash] keys are headers, values are arrays

# File lib/eco/csv/table.rb, line 158
def columns_hash
  columns.map do |col|
    [col.first, col[1..-1]]
  end.to_h
end
delete_column(i) click to toggle source

@return [Eco::CSV::Table]

# File lib/eco/csv/table.rb, line 101
def delete_column(i)
  csv_cols = columns
  csv_cols.delete(i)
  columns_to_table(csv_cols)
end
delete_duplicates!() click to toggle source

It removes all rows where all columns' values are the same

# File lib/eco/csv/table.rb, line 123
def delete_duplicates!
  unique_rows = []
  self.by_row!.delete_if do |row|
    unique_rows.any? {|done| equal_rows?(row, done)}.tap do |found|
      unique_rows << row unless found
    end
  end
end
duplicated_header_names() click to toggle source

@return [Array<String>] list of duplicated header names

# File lib/eco/csv/table.rb, line 53
def duplicated_header_names
  header = self.headers
  header.select {|e| header.count(e) > 1}.uniq
end
empty?() click to toggle source
# File lib/eco/csv/table.rb, line 146
def empty?
  length < 1
end
equal_rows?(row1, row2) click to toggle source

@param row1 [CSV:Row] row to be compared @param row2 [CSV:Row] row to be compared @param [Boolean] `true` if all values of `row1` are as of `row2`

# File lib/eco/csv/table.rb, line 135
def equal_rows?(row1, row2)
  row1.fields.zip(row2.fields).all? do |(v1, v2)|
    v1 == v2
  end
end
group_by(&block) click to toggle source

@return [Hash] where keys are the groups and the values a `Eco::CSV::Table`

# File lib/eco/csv/table.rb, line 12
def group_by(&block)
  rows.group_by(&block).transform_values do |rows|
    self.class.new(rows)
  end
end
length() click to toggle source

@return [Integer] total number of rows not including the header

# File lib/eco/csv/table.rb, line 142
def length
  to_a.length - 1
end
merge_same_header_names() { |value, out, name| ... } click to toggle source

@return [Eco::CSV::Table]

# File lib/eco/csv/table.rb, line 29
def merge_same_header_names
  dups = self.duplicated_header_names
  out_rows = self.map do |row|
    row.to_a.each_with_object({}) do |(name, value), out|
      if dups.include?(name) && out.key?(name)
        if block_given?
          yield(value, out[name], name)
        else
          # resolve
          value || out[name]
        end
      elsif out.key?(name)
        out[name]
      else
        value
      end.tap do |final_value|
        out[name] = final_value
      end
    end
  end
  self.class.new(out_rows)
end
rows() click to toggle source

@return [Array<::CSV::Row>]

# File lib/eco/csv/table.rb, line 116
def rows
  [].tap do |out|
    self.each {|row| out << row}
  end
end
slice(*index) click to toggle source

Slices the selected rows @return [Eco::CSV::Table]

# File lib/eco/csv/table.rb, line 74
def slice(*index)
  case index.first
  when Range, Numeric
    self.class.new(rows.slice(index.first))
  else
    self
  end
end
slice_columns(*index) click to toggle source

@return [Eco::CSV::Table]

# File lib/eco/csv/table.rb, line 84
def slice_columns(*index)
  case index.first
  when Range, Numeric
    columns_to_table(columns.slice(index.first))
  when String
    csv_cols = columns
    csv_cols = index.each_with_object([]) do |name, cols|
      col = csv_cols.find {|col| col.first == name}
      cols << col if col
    end
    columns_to_table(csv_cols)
  else
    self
  end
end
to_a_h() click to toggle source

Returns an array of row hashes @note it will override columns with same header

# File lib/eco/csv/table.rb, line 166
def to_a_h
  rows.map(&:to_h)
end
to_array_of_hashes() click to toggle source

@see to_a_h

# File lib/eco/csv/table.rb, line 171
def to_array_of_hashes
  to_a_h
end
transform_headers() { |first| ... } click to toggle source

@return [Eco::CSV::Table]

# File lib/eco/csv/table.rb, line 19
def transform_headers
  header = self.headers
  cols   = self.columns
  cols.each do |col|
    col[0] = yield(col.first)
  end
  columns_to_table(cols)
end
transform_values() { |row| ... } click to toggle source

@return [Eco::CSV::Table]

# File lib/eco/csv/table.rb, line 59
def transform_values
  transformed_rows = rows.map do |row|
    res = yield(row)
    case res
    when Array
      ::CSV::Row.new(row.headers, res)
    when ::CSV::Row
      res
    end
  end
  self.class.new(transformed_rows)
end

Private Instance Methods

columns_to_table(columns_array) click to toggle source
# File lib/eco/csv/table.rb, line 177
def columns_to_table(columns_array)
  data = to_rows_array(columns_array.transpose)
  self.class.new(data)
end
to_rows_array(data) click to toggle source
# File lib/eco/csv/table.rb, line 182
def to_rows_array(data)
  case data
  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)
  when Enumerable
    data = data.dup.compact
    return data unless data.count > 0
    sample = data.first

    case sample
    when ::CSV::Row
      data
    when Array
      headers  = data.shift
      data.map do |arr_row|
        ::CSV::Row.new(headers, arr_row)
      end.compact
    when Hash
      headers     = sample.keys
      headers_str = headers.map(&:to_s)
      data.map do |hash|
        ::CSV::Row.new(headers_str, hash.values_at(*headers))
      end.compact
    else
      raise "Expected data that can be transformed into Array<::CSV::Row>. Given 'Enumerable' of '#{sample.class}'"
    end
  else
    raise "Input type not supported. Given: #{data.class}"
  end
end