Class: Charty::TableAdapters::HashAdapter

Inherits:
BaseAdapter
  • Object
show all
Defined in:
lib/charty/table_adapters/hash_adapter.rb

Instance Attribute Summary collapse

Attributes inherited from BaseAdapter

#columns, #index

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from BaseAdapter

#==, #column?, #column_names, #drop_na, #group_by, #melt, #sort_values

Constructor Details

#initialize(data, columns: nil, index: nil) ⇒ HashAdapter

Returns a new instance of HashAdapter.


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/charty/table_adapters/hash_adapter.rb', line 61

def initialize(data, columns: nil, index: nil)
  case data
  when Hash
    arrays = data.values
    columns ||= data.keys
  when Array
    case data[0]
    when Numeric, String, Time, Date
      arrays = [data]
    when Hash
      columns ||= data.map(&:keys).inject(&:|)
      arrays = columns.map { [] }
      data.each do |record|
        columns.each_with_index do |key, i|
          arrays[i] << record[key]
        end
      end
    when Vector
      arrays = data
    when self.class.method(:array?)
      unsupported_data_format unless data.all?(&self.class.method(:array?))
      arrays = data.map(&:to_a).transpose
    else
      unsupported_data_format
    end
  when ->(x) { defined?(CSV::Table) && x.is_a?(CSV::Table) }
    columns ||= data.headers
    arrays = data.headers.map {|x| data[x] }
  else
    unsupported_data_format
  end

  unless arrays.empty?
    arrays, columns, index = check_data(arrays, columns, index)
  end

  @data = arrays.map.with_index {|a, i| [columns[i], a] }.to_h
  self.columns = columns unless columns.nil?
  self.index = index unless index.nil?
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.


150
151
152
# File 'lib/charty/table_adapters/hash_adapter.rb', line 150

def data
  @data
end

Class Method Details

.array?(data) ⇒ Boolean

Returns:

  • (Boolean)

28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/charty/table_adapters/hash_adapter.rb', line 28

def self.array?(data)
  case data
  when Charty::Vector
    true
  # TODO: Use vector adapter to detect them:
  when Array, method(:daru_vector?), method(:narray_vector?), method(:nmatrix_vector?),
       method(:numpy_vector?), method(:pandas_series?)
    true
  else
    false
  end
end

.daru_vector?(x) ⇒ Boolean

Returns:

  • (Boolean)

41
42
43
# File 'lib/charty/table_adapters/hash_adapter.rb', line 41

def self.daru_vector?(x)
  defined?(Daru::Vector) && x.is_a?(Daru::Vector)
end

.narray_vector?(x) ⇒ Boolean

Returns:

  • (Boolean)

45
46
47
# File 'lib/charty/table_adapters/hash_adapter.rb', line 45

def self.narray_vector?(x)
  defined?(Numo::NArray) && x.is_a?(Numo::NArray) && x.ndim == 1
end

.nmatrix_vector?(x) ⇒ Boolean

Returns:

  • (Boolean)

49
50
51
# File 'lib/charty/table_adapters/hash_adapter.rb', line 49

def self.nmatrix_vector?(x)
  defined?(NMatrix) && x.is_a?(NMatrix) && x.dim == 1
end

.numpy_vector?(x) ⇒ Boolean

Returns:

  • (Boolean)

53
54
55
# File 'lib/charty/table_adapters/hash_adapter.rb', line 53

def self.numpy_vector?(x)
  defined?(Numpy::NDArray) && x.is_a?(Numpy::NDArray) && x.ndim == 1
end

.pandas_series?(x) ⇒ Boolean

Returns:

  • (Boolean)

57
58
59
# File 'lib/charty/table_adapters/hash_adapter.rb', line 57

def self.pandas_series?(x)
  defined?(Pandas::Series) && x.is_a?(Pandas::Series)
end

.supported?(data) ⇒ Boolean

Returns:

  • (Boolean)

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/charty/table_adapters/hash_adapter.rb', line 8

def self.supported?(data)
  case data
  when []
    true
  when Array
    case data[0]
    when Numeric, String, Time, Date
      true
    when Hash
      data.all? {|el| el.is_a? Hash }
    when method(:array?)
      data.all?(&method(:array?))
    end
  when Hash
    true
  when ->(x) { defined?(CSV::Table) && x.is_a?(CSV::Table) }
    true
  end
end

Instance Method Details

#[](row, column) ⇒ Object


176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/charty/table_adapters/hash_adapter.rb', line 176

def [](row, column)
  if row
    @data[column][row]
  else
    case column
    when Array
      slice_data = column.map { |cn|
        [cn, self[nil, cn]]
      }.to_h
      return Charty::Table.new(slice_data, index: self.index)
    when Symbol
      sym_key = column
      str_key = column.to_s
    else
      str_key = String.try_convert(column)
      sym_key = str_key.to_sym
    end

    column_data = if @data.key?(sym_key)
                    @data[sym_key]
                  else
                    @data[str_key]
                  end
    Vector.new(column_data, index: index, name: column)
  end
end

#[]=(key, values) ⇒ Object


203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/charty/table_adapters/hash_adapter.rb', line 203

def []=(key, values)
  case key
  when Symbol
    str_key = key.to_s
    sym_key = key
  else
    str_key = key.to_str
    sym_key = str_key.to_sym
  end

  orig_values = values
  values = Vector.try_convert(values)
  if values.nil?
    raise ArgumentError,
          "`values` must be convertible to Charty::Vector"
  end

  if values.length != self.length
    raise ArgumentError,
          "`values` length does not match the length of the table"
  end

  if @data.key?(sym_key)
    @data[sym_key] = values
  elsif @data.key?(str_key)
    @data[str_key] = values
  elsif key == sym_key
    @data[sym_key] = values
    new_column = sym_key
  else
    @data[str_key] = values
    new_column = sym_key
  end

  if new_column
    self.columns = Index.new([*self.columns, new_column])
  end

  values
end

#column_lengthObject


163
164
165
# File 'lib/charty/table_adapters/hash_adapter.rb', line 163

def column_length
  data.length
end

#compare_data_equality(other) ⇒ Object


167
168
169
170
171
172
173
174
# File 'lib/charty/table_adapters/hash_adapter.rb', line 167

def compare_data_equality(other)
  case other
  when DaruAdapter, PandasDataFrameAdapter
    other.compare_data_equality(self)
  else
    super
  end
end

#eachObject


244
245
246
247
248
249
250
251
# File 'lib/charty/table_adapters/hash_adapter.rb', line 244

def each
  i, n = 0, shape[0]
  while i < n
    record = @data.map {|k, v| v[i] }
    yield record
    i += 1
  end
end

#lengthObject


154
155
156
157
158
159
160
161
# File 'lib/charty/table_adapters/hash_adapter.rb', line 154

def length
  case
  when column_names.empty?
    0
  else
    data[column_names[0]].size
  end
end

#reset_indexObject


253
254
255
256
# File 'lib/charty/table_adapters/hash_adapter.rb', line 253

def reset_index
  index_name = index.name || :index
  Charty::Table.new({ index_name => index.to_a }.merge(data))
end