Class: Daru::Index

Inherits:
Object show all
Includes:
Enumerable
Defined in:
lib/daru/index.rb

Direct Known Subclasses

CategoricalIndex, DateTimeIndex, MultiIndex

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(index) ⇒ Index

Returns a new instance of Index.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/daru/index.rb', line 52

def initialize index
  index =
    case index
    when nil
      []
    when Integer
      index.times.to_a
    when Enumerable
      index.to_a
    else
      raise ArgumentError,
        "Cannot create index from #{index.class} #{index.inspect}"
    end

  @relation_hash = index.each_with_index.to_h.freeze
  @keys = @relation_hash.keys
  @size = @relation_hash.size
end

Instance Attribute Details

#relation_hashObject (readonly)

Returns the value of attribute relation_hash.



50
51
52
# File 'lib/daru/index.rb', line 50

def relation_hash
  @relation_hash
end

#sizeObject (readonly)

Returns the value of attribute size.



50
51
52
# File 'lib/daru/index.rb', line 50

def size
  @size
end

Class Method Details

.__new__Object



12
# File 'lib/daru/index.rb', line 12

alias :__new__ :new

._load(data) ⇒ Object



210
211
212
213
214
# File 'lib/daru/index.rb', line 210

def self._load data
  h = Marshal.load data

  Daru::Index.new(h[:relation_hash].keys)
end

.coerce(maybe_index) ⇒ Object



35
36
37
# File 'lib/daru/index.rb', line 35

def self.coerce maybe_index
  maybe_index.is_a?(Index) ? maybe_index : Daru::Index.new(maybe_index)
end

.inherited(subclass) ⇒ Object



14
15
16
17
18
# File 'lib/daru/index.rb', line 14

def inherited subclass
  class << subclass
    alias :new :__new__
  end
end

.new(*args, &block) ⇒ Object

We over-ride the .new method so that any sort of Index can be generated from Daru::Index based on the types of arguments supplied.



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/daru/index.rb', line 23

def self.new *args, &block
  # FIXME: I'm not sure this clever trick really deserves our attention.
  # Most of common ruby libraries just avoid it in favor of usual
  # factor method, like `Index.create`. When `Index.new(...).class != Index`
  # it just leads to confusion and surprises. - zverok, 2016-05-18
  source = args.first

  MultiIndex.try_from_tuples(source) ||
    DateTimeIndex.try_create(source) ||
    allocate.tap { |i| i.send :initialize, *args, &block }
end

Instance Method Details

#&(other) ⇒ Object

Produce a new index from the set intersection of two indexes



177
178
179
# File 'lib/daru/index.rb', line 177

def & other
  Index.new(to_a & other.to_a)
end

#==(other) ⇒ Object



71
72
73
74
75
76
# File 'lib/daru/index.rb', line 71

def ==(other)
  return false if self.class != other.class || other.size != @size

  @relation_hash.keys == other.to_a &&
    @relation_hash.values == other.relation_hash.values
end

#[](key, *rest) ⇒ Object



78
79
80
81
82
83
84
85
86
87
# File 'lib/daru/index.rb', line 78

def [](key, *rest)
  case
  when key.is_a?(Range)
    by_range key
  when !rest.empty?
    by_multi_key key, *rest
  else
    by_single_key key
  end
end

#_dumpObject



206
207
208
# File 'lib/daru/index.rb', line 206

def _dump(*)
  Marshal.dump(relation_hash: @relation_hash)
end

#add(*indexes) ⇒ Object



202
203
204
# File 'lib/daru/index.rb', line 202

def add *indexes
  Daru::Index.new(to_a + indexes)
end

#at(*positions) ⇒ object

Takes positional values and returns subset of the self

capturing the indexes at mentioned positions

Examples:

idx = Daru::Index.new [:a, :b, :c]
idx.at 0, 1
# => #<Daru::Index(2): {a, b}>

Parameters:

  • positional (Array<Integer>)

    values

Returns:

  • (object)

    index object



139
140
141
142
143
144
145
146
147
# File 'lib/daru/index.rb', line 139

def at *positions
  positions = preprocess_positions(*positions)
  validate_positions(*positions)
  if positions.is_a? Integer
    key(positions)
  else
    self.class.new positions.map(&method(:key))
  end
end

#conformObject

Provide an Index for sub vector produced

Parameters:

  • input_indexes (Array)

    the input by user to index the vector

Returns:

  • (Object)

    the Index object for sub vector produced



220
221
222
# File 'lib/daru/index.rb', line 220

def conform(*)
  self
end

#dupObject



198
199
200
# File 'lib/daru/index.rb', line 198

def dup
  Daru::Index.new @relation_hash.keys
end

#each(&block) ⇒ Object



39
40
41
42
43
44
# File 'lib/daru/index.rb', line 39

def each(&block)
  return to_enum(:each) unless block_given?

  @relation_hash.each_key(&block)
  self
end

#empty?Boolean

Returns:

  • (Boolean)


194
195
196
# File 'lib/daru/index.rb', line 194

def empty?
  @relation_hash.empty?
end

#include?(index) ⇒ Boolean

Returns:

  • (Boolean)


190
191
192
# File 'lib/daru/index.rb', line 190

def include? index
  @relation_hash.key? index
end

#inspect(threshold = 20) ⇒ Object



149
150
151
152
153
154
155
# File 'lib/daru/index.rb', line 149

def inspect threshold=20
  if size <= threshold
    "#<#{self.class}(#{size}): {#{to_a.join(', ')}}>"
  else
    "#<#{self.class}(#{size}): {#{to_a.first(threshold).join(', ')} ... #{to_a.last}}>"
  end
end

#key(value) ⇒ Object



185
186
187
188
# File 'lib/daru/index.rb', line 185

def key(value)
  return nil unless value.is_a?(Numeric)
  @keys[value]
end

#map(&block) ⇒ Object



46
47
48
# File 'lib/daru/index.rb', line 46

def map(&block)
  to_a.map(&block)
end

#pos(*indexes) ⇒ Object

Note:

If the arugent is both a valid index and a valid position, it will treated as valid index

Returns positions given indexes or positions

Examples:

x = Daru::Index.new [:a, :b, :c]
x.pos :a, 1
# => [0, 1]

Parameters:

  • *indexes (Array<object>)

    indexes or positions



109
110
111
112
113
114
115
116
117
# File 'lib/daru/index.rb', line 109

def pos *indexes
  indexes = preprocess_range(indexes.first) if indexes.first.is_a? Range

  if indexes.size == 1
    self[indexes.first]
  else
    indexes.map { |index| by_single_key index }
  end
end

#reorder(new_order) ⇒ Object



224
225
226
227
# File 'lib/daru/index.rb', line 224

def reorder(new_order)
  from = to_a
  self.class.new(new_order.map { |i| from[i] })
end

#slice(*args) ⇒ Object



157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/daru/index.rb', line 157

def slice *args
  start = args[0]
  en = args[1]

  if start.is_a?(Integer) && en.is_a?(Integer)
    Index.new @keys[start..en]
  else
    start_idx = @relation_hash[start]
    en_idx    = @relation_hash[en]

    Index.new @keys[start_idx..en_idx]
  end
end

#subset(*indexes) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
# File 'lib/daru/index.rb', line 119

def subset *indexes
  if indexes.first.is_a? Range
    slice indexes.first.begin, indexes.first.end
  elsif include? indexes.first
    # Assume 'indexes' contain indexes not positions
    Daru::Index.new indexes
  else
    # Assume 'indexes' contain positions not indexes
    Daru::Index.new indexes.map { |k| key k }
  end
end

#to_aObject



181
182
183
# File 'lib/daru/index.rb', line 181

def to_a
  @relation_hash.keys
end

#valid?(*indexes) ⇒ true, false

Returns true if all arguments are either a valid category or position

Examples:

idx.valid? :a, 2
# => true
idx.valid? 3
# => false

Parameters:

  • *indexes (Array<object>)

    categories or positions

Returns:

  • (true, false)


97
98
99
# File 'lib/daru/index.rb', line 97

def valid? *indexes
  indexes.all? { |i| to_a.include?(i) || (i.is_a?(Numeric) && i < size) }
end

#|(other) ⇒ Object

Produce new index from the set union of two indexes.



172
173
174
# File 'lib/daru/index.rb', line 172

def |(other)
  Index.new(to_a | other.to_a)
end