An N-dimensional table object, comprising structure and values.
The Structure of this table
Deprecated synonym for NTable.from_json_object
# File lib/ntable/construction.rb, line 316 def from_json_object(json_) ::NTable.from_json_object(json_) end
Deprecated synonym for NTable.from_nested_object
# File lib/ntable/construction.rb, line 330 def from_nested_object(obj_, field_opts_=[], opts_={}) ::NTable.from_nested_object(obj_, field_opts_, opts_) end
This is a low-level table creation mechanism. Generally, you should use NTable.create instead.
# File lib/ntable/table.rb, line 51 def initialize(structure_, data_={}) @structure = structure_ @structure.lock! size_ = @structure.size if (load_ = data_[:load]) load_size_ = load_.size if load_size_ > size_ @vals = load_[0, size_] elsif load_size_ < size_ @vals = load_ + ::Array.new(size_ - load_size_, data_[:fill]) else @vals = load_.dup end elsif (acquire_ = data_[:acquire]) @vals = acquire_ else @vals = ::Array.new(size_, data_[:fill]) end @offset = data_[:offset].to_i @parent = data_[:parent] end
Deprecated synonym for NTable.parse_json
# File lib/ntable/construction.rb, line 323 def parse_json(json_) ::NTable.parse_json(json_) end
Returns true if the two tables are equivalent in data but not necessarily parentage. The structure of a shared slice may be equivalent, in this sense, to the “same” table created from scratch with no parent.
# File lib/ntable/table.rb, line 116 def ==(rhs_) if self.equal?(rhs_) true elsif rhs_.is_a?(Table) if rhs_.parent || self.parent if @structure == rhs_.structure riter_ = rhs_.each liter_ = self.each @structure.size.times do return false unless liter_.next == riter_.next end true else false end else rhs_.structure.eql?(@structure) && rhs_.instance_variable_get(:@vals).eql?(@vals) end else false end end
Returns an array of AxisInfo objects representing all the axes of the structure of this table.
# File lib/ntable/table.rb, line 192 def all_axes @structure.all_axes end
Returns the AxisInfo object representing the given axis. The axis must be specified by 0-based index or by name string. Returns nil if there is no such axis.
# File lib/ntable/table.rb, line 184 def axis(axis_) @structure.axis(axis_) end
Decomposes this table, breaking it into a set of lower-dimensional tables, all arranged in a table. For example, you could decompose a two-dimensional table into a one-dimensional table of one-dimensional tables. You must provide an array of axis specifications (indexes or names) identifying which axes should be part of the lower-dimensional tables.
# File lib/ntable/table.rb, line 522 def decompose(*axes_) axes_ = axes_.flatten axis_indexes_ = [] axes_.each do |a_| if (ainfo_ = @structure.axis(a_)) axis_indexes_ << ainfo_.axis_index else raise UnknownAxisError, "Unknown axis: #{a_.inspect}" end end inner_struct_ = @structure.substructure_including(axis_indexes_) outer_struct_ = @structure.substructure_omitting(axis_indexes_) vec_ = ::Array.new(outer_struct_.dim, 0) tables_ = (0...outer_struct_.size).map do |i_| t_ = Table.new(inner_struct_, :acquire => @vals, :offset => @offset + outer_struct_._compute_offset_for_vector(vec_), :parent => self) outer_struct_._inc_vector(vec_) t_ end Table.new(outer_struct_.unlocked_copy, :acquire => tables_) end
Decompose this table using the given axes, and then reduce each inner table, returning a table of the reduction values.
# File lib/ntable/table.rb, line 549 def decompose_reduce(decompose_axes_, *reduce_args_, &block_) decompose(decompose_axes_).map{ |sub_| sub_.reduce(*reduce_args_, &block_) } end
Decompose this table using the given axes, and then reduce each inner table with position, returning a table of the reduction values.
# File lib/ntable/table.rb, line 557 def decompose_reduce_with_position(decompose_axes_, *reduce_args_, &block_) decompose(decompose_axes_).map{ |sub_| sub_.reduce_with_position(*reduce_args_, &block_) } end
True if this is a degenerate (scalar) table with a single cell and no dimensions.
# File lib/ntable/table.rb, line 175 def degenerate? @structure.degenerate? end
The number of dimensions/axes in this table.
# File lib/ntable/table.rb, line 160 def dim @structure.dim end
Iterate over all table cells, in order, and call the given block. If no block is given, an ::Enumerator is returned.
# File lib/ntable/table.rb, line 325 def each(&block_) if @parent if block_given? vec_ = ::Array.new(@structure.dim, 0) @structure.size.times do yield(@vals[@offset + @structure._compute_offset_for_vector(vec_)]) @structure._inc_vector(vec_) end else enum_for end else @vals.each(&block_) end end
Iterate over all table cells, and call the given block with the value and the Structure::Position for the cell.
# File lib/ntable/table.rb, line 345 def each_with_position vec_ = ::Array.new(@structure.dim, 0) @structure.size.times do yield(@vals[@offset + @structure._compute_offset_for_vector(vec_)], Structure::Position.new(@structure, vec_)) @structure._inc_vector(vec_) end self end
True if this table has no cells.
# File lib/ntable/table.rb, line 167 def empty? @structure.empty? end
Returns true if the two tables are equivalent, both in the data and in the parentage. The structure of a shared slice is not equivalent, in this sense, to the “same” table created from scratch, because the former is a “sparse” subset of a parent whereas the latter is not.
# File lib/ntable/table.rb, line 102 def eql?(rhs_) self.equal?(rhs_) || rhs_.is_a?(Table) && @structure.eql?(rhs_.structure) && @parent.eql?(rhs_.parent) && rhs_.instance_variable_get(:@offset) == @offset && rhs_.instance_variable_get(:@vals).eql?(@vals) end
Fill all table cells with the given value.
You cannot load values into a table with a parent. Instead, you must modify the parent, and those changes will be reflected in the child.
Returns self so calls can be chained.
# File lib/ntable/table.rb, line 315 def fill!(value_) raise TableLockedError if @parent @vals.fill(value_) self end
Returns the value in the cell at the given coordinates, which may be given as labels or as 0-based row indexes. You may specify the cell as an array of coordinates, or as a hash mapping axis name or axis index to coordinate.
For example, for a typical database result set with an axis called “row” of numerically identified rows, and an axis called “col” with string-named columns, these call sequences are equivalent:
get(3, 'name') get([3, 'name']) get(:row => 3, :col => 'name') get(0 => 3, 1 => 'name')
Alternately, you can provide row numbers (0-based) instead. If, for example, “name” is the second column (corresponding to index 1), then the following queries are also equivalent:
get(3, 1) get(:row => 3, :col => 1)
For axes whose labels are integers (for example, a numerically identified axis such as IndexedAxis), it is ambiguous whether a value is intended as a label or an index. In this case, NTable defalts to assuming the value is a label. If you want to force a value to be treated as a 0-based row index, wrap it in a call to NTable.index, as follows:
get(NTable.index(3), 1)
Raises NoSuchCellError if the coordinates do not exist.
# File lib/ntable/table.rb, line 239 def get(*args_) offset_ = _offset_for_args(args_) unless offset_ raise NoSuchCellError end @vals[@offset + offset_] end
Standard hash value
# File lib/ntable/table.rb, line 142 def hash @structure.hash + @vals.hash + @offset.hash + @parent.hash end
Returns a boolean indicating whether the given cell coordinates actually exist. The arguments use the same syntax as for #get.
# File lib/ntable/table.rb, line 252 def include?(*args_) _offset_for_args(args_) ? true : false end
Basic output.
# File lib/ntable/table.rb, line 89 def inspect axes_ = @structure.all_axes.map{ |a_| "#{a_.axis_name}:#{a_.axis_object.class.name.sub('NTable::', '')}" } "#<#{self.class}:0x#{object_id.to_s(16)} #{axes_.join(', ')}#{@parent ? ' (sub)' : ''} #{@vals.inspect}>" end
Load an array of values into the table cells, in order.
You cannot load values into a table with a parent. Instead, you must modify the parent, and those changes will be reflected in the child.
Returns self so calls can be chained.
# File lib/ntable/table.rb, line 293 def load!(vals_) raise TableLockedError if @parent is_ = vals_.size vs_ = @vals.size if is_ < vs_ @vals = vals_.dup + @vals[is_..-1] elsif is_ > vs_ @vals = vals_[0,vs_] else @vals = vals_.dup end self end
Return a new table whose structure is the same as this table, and whose values are given by mapping the current table’s values through the given block.
# File lib/ntable/table.rb, line 360 def map(&block_) if @parent vec_ = ::Array.new(@structure.dim, 0) nvals_ = (0...@structure.size).map do |i_| val_ = yield(@vals[@offset + @structure._compute_offset_for_vector(vec_)]) @structure._inc_vector(vec_) val_ end Table.new(@structure.unlocked_copy, :acquire => nvals_) else Table.new(@structure, :acquire => @vals.map(&block_)) end end
Modify the current table in place, mapping values through the given block.
You cannot set values in a table with a parent. Instead, you must modify the parent, and those changes will be reflected in the child.
# File lib/ntable/table.rb, line 397 def map!(&block_) raise TableLockedError if @parent @vals.map!(&block_) self end
Same as #map except the block is passed the current table’s value for each cell, and the cell’s Structure::Position.
# File lib/ntable/table.rb, line 378 def map_with_position nstructure_ = @structure.parent ? @structure.unlocked_copy : @structure vec_ = ::Array.new(@structure.dim, 0) nvals_ = (0...@structure.size).map do |i_| nval_ = yield(@vals[@offset + @structure._compute_offset_for_vector(vec_)], Structure::Position.new(@structure, vec_)) @structure._inc_vector(vec_) nval_ end Table.new(nstructure_, :acquire => nvals_) end
Modify the current table in place, mapping values through the given block, which takes both the old value and the Structure::Position.
You cannot set values in a table with a parent. Instead, you must modify the parent, and those changes will be reflected in the child.
# File lib/ntable/table.rb, line 410 def map_with_position! raise TableLockedError if @parent vec_ = ::Array.new(@structure.dim, 0) @vals.map! do |val_| nval_ = yield(val_, Structure::Position.new(@structure, vec_)) @structure._inc_vector(vec_) nval_ end self end
Return the parent of this table. A table with a parent shares the parent’s data, and cannot have its data modified directly. Instead, if the parent table is modified, the changes are reflected in the child. Returns nil if this table has no parent.
# File lib/ntable/table.rb, line 202 def parent @parent end
Performs a reduce on the entire table and returns the result. You may use one of the following call sequences:
Reduces using the given block as the reduction function. The first element in the table is used as the initial accumulator.
Reduces using the given block as the reduction function, with the given initial value for the accumulator.
[reduce(:method-name)
Reduces using the given binary operator or method name as the reduction function. If it is a method, the method must take a single argument for the right-hand-side of the operation. The first element in the table is used as the initial accumulator.
[reduce(initial, :method-name)
Reduces using the given binary operator or method name as the reduction function. If it is a method, the method must take a single argument for the right-hand-side of the operation. The given initial accumulator value is used.
# File lib/ntable/table.rb, line 442 def reduce(*args_) nothing_ = ::Object.new if block_given? case args_.size when 1 obj_ = args_.first when 0 obj_ = nothing_ else raise ::ArgumentError, "Wrong number of arguments" end each do |e_| if nothing_ == obj_ obj_ = e_ else obj_ = yield(obj_, e_) end end else sym_ = args_.pop case args_.size when 1 obj_ = args_.first when 0 obj_ = nothing_ else raise ::ArgumentError, "Wrong number of arguments" end each do |e_| if nothing_ == obj_ obj_ = e_ else obj_ = obj_.send(sym_, e_) end end end nothing_ == obj_ ? nil : obj_ end
Performs a reduce on the entire table and returns the result. You may use one of the following call sequences:
Reduces using the given block as the reduction function. The first element in the table is used as the initial accumulator.
Reduces using the given block as the reduction function, with the given initial value for the accumulator.
# File lib/ntable/table.rb, line 493 def reduce_with_position(*args_) nothing_ = ::Object.new case args_.size when 1 obj_ = args_.first when 0 obj_ = nothing_ else raise ::ArgumentError, "Wrong number of arguments" end each_with_position do |val_, pos_| if nothing_ == obj_ obj_ = val_ else obj_ = yield(obj_, val_, pos_) end end nothing_ == obj_ ? nil : obj_ end
Set the value in the cell at the given coordinates. If a block is given, it is passed the current value and expects the new value to be its result. If no block is given, the last argument is taken to be the new value. The remaining arguments identify the cell, using the same syntax as for #get.
You cannot set a value in a table with a parent. Instead, you must modify the parent, and those changes will be reflected in the child.
Raises NoSuchCellError if the coordinates do not exist.
Returns self so calls can be chained.
# File lib/ntable/table.rb, line 270 def set!(*args_, &block_) raise TableLockedError if @parent value_ = block_ ? nil : args_.pop offset_ = _offset_for_args(args_) unless offset_ raise NoSuchCellError end if block_ value_ = block_.call(@vals[@offset + offset_]) end @vals[@offset + offset_] = value_ self end
The number of cells in this table.
# File lib/ntable/table.rb, line 153 def size @structure.size end
Returns a table containing a “slice” of this table. The given hash should be keyed by axis indexes or axis names, and should provide specific values for zero or more dimensions, which provides the constraints for the slice.
Returns a new table independent of this table. The new table can have cell values modified independently of this table.
# File lib/ntable/table.rb, line 600 def slice(hash_) shared_slice(hash_).dup end
Returns a JSON serialization of this table, as an unparsed string.
# File lib/ntable/table.rb, line 615 def to_json to_json_object.to_json end
Returns a JSON serialization of this table, as an object. If you need to output a JSON string, you must unparse separately.
# File lib/ntable/table.rb, line 608 def to_json_object {'type' => 'ntable', 'axes' => @structure.to_json_array, 'values' => @parent ? _compacted_vals : @vals} end
Returns a nested-object (nested arrays and hashes) serialization of this table.
# File lib/ntable/table.rb, line 623 def to_nested_object(opts_={}) if @structure.degenerate? @vals[@offset] else _to_nested_obj(0, ::Array.new(@structure.dim, 0), opts_) end end