class NTable::Table

An N-dimensional table object, comprising structure and values.

Attributes

structure[R]

The Structure of this table

Public Class Methods

from_json_object(json_) click to toggle source

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
from_nested_object(obj_, field_opts_=[], opts_={}) click to toggle source

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
new(structure_, data_={}) click to toggle source

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
parse_json(json_) click to toggle source

Deprecated synonym for NTable.parse_json

# File lib/ntable/construction.rb, line 323
def parse_json(json_)
  ::NTable.parse_json(json_)
end

Public Instance Methods

==(rhs_) click to toggle source

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
[](*args_) click to toggle source
Alias for: get
[]=(*args_, &block_) click to toggle source
Alias for: set!
all_axes() click to toggle source

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
axis(axis_) click to toggle source

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
decompose(*axes_) click to toggle source

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_reduce(decompose_axes_, *reduce_args_, &block_) click to toggle source

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_reduce_with_position(decompose_axes_, *reduce_args_, &block_) click to toggle source

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
degenerate?() click to toggle source

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
dim() click to toggle source

The number of dimensions/axes in this table.

# File lib/ntable/table.rb, line 160
def dim
  @structure.dim
end
each() { |vals| ... } click to toggle source

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
each_with_position() { |vals, position| ... } click to toggle source

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
empty?() click to toggle source

True if this table has no cells.

# File lib/ntable/table.rb, line 167
def empty?
  @structure.empty?
end
eql?(rhs_) click to toggle source

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!(value_) click to toggle source

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
get(*args_) click to toggle source

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
Also aliased as: []
hash() click to toggle source

Standard hash value

# File lib/ntable/table.rb, line 142
def hash
  @structure.hash + @vals.hash + @offset.hash + @parent.hash
end
include?(*args_) click to toggle source

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
inject(*args_) click to toggle source
Alias for: reduce
inject_with_position(*args_) click to toggle source
inspect() click to toggle source

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
Also aliased as: to_s
load!(vals_) click to toggle source

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
map() { |vals| ... } click to toggle source

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
map!(&block_) click to toggle source

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
map_with_position() { |vals, position| ... } click to toggle source

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
map_with_position!() { |val_, position| ... } click to toggle source

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
parent() click to toggle source

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
reduce(*args_) { |obj_, e_| ... } click to toggle source

Performs a reduce on the entire table and returns the result. You may use one of the following call sequences:

reduce{ |accumulator, value| block }

Reduces using the given block as the reduction function. The first element in the table is used as the initial accumulator.

reduce(initial){ |accumulator, value| block }

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
Also aliased as: inject
reduce_with_position(*args_) { |obj_, val_, pos_| ... } click to toggle source

Performs a reduce on the entire table and returns the result. You may use one of the following call sequences:

#reduce_with_position{ |accumulator, value, position| block }

Reduces using the given block as the reduction function. The first element in the table is used as the initial accumulator.

#reduce_with_position(initial){ |accumulator, value, position| block }

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
Also aliased as: inject_with_position
set!(*args_, &block_) click to toggle source

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
Also aliased as: []=
shared_slice(hash_) click to toggle source

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 slice table whose parent is this table. Because the slice table has a parent, it is not mutable because it shares data with this table. If this table has values modified, the slice data will reflect those changes.

# File lib/ntable/table.rb, line 572
def shared_slice(hash_)
  offset_ = @offset
  select_set_ = {}
  hash_.each do |k_, v_|
    if (ainfo_ = @structure.axis(k_))
      aindex_ = ainfo_.axis_index
      unless select_set_.include?(aindex_)
        lindex_ = ainfo_.index(v_)
        if lindex_
          offset_ += ainfo_.step * lindex_
          select_set_[aindex_] = true
        end
      end
    end
  end
  Table.new(@structure.substructure_omitting(select_set_.keys),
    :acquire => @vals, :offset => offset_, :parent => self)
end
size() click to toggle source

The number of cells in this table.

# File lib/ntable/table.rb, line 153
def size
  @structure.size
end
slice(hash_) click to toggle source

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
to_json() click to toggle source

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
to_json_object() click to toggle source

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
to_nested_object(opts_={}) click to toggle source

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
to_s() click to toggle source
Alias for: inspect