Class: Daru::Index

Inherits:
Object show all
Includes:
Enumerable
Defined in:
lib/daru/index/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.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/daru/index/index.rb', line 48

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.



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

def relation_hash
  @relation_hash
end

#sizeObject (readonly)

Returns the value of attribute size.



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

def size
  @size
end

Class Method Details

.__new__Object



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

alias :__new__ :new

._load(data) ⇒ Object



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

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/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/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/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



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

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

#==(other) ⇒ Object



67
68
69
70
71
72
# File 'lib/daru/index/index.rb', line 67

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



74
75
76
77
78
79
80
81
82
83
# File 'lib/daru/index/index.rb', line 74

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



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

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

#add(*indexes) ⇒ Object



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

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



135
136
137
138
139
140
141
142
143
# File 'lib/daru/index/index.rb', line 135

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



216
217
218
# File 'lib/daru/index/index.rb', line 216

def conform(*)
  self
end

#dupObject



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

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

#each(&block) ⇒ Object



39
40
41
42
43
44
# File 'lib/daru/index/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)


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

def empty?
  @relation_hash.empty?
end

#include?(index) ⇒ Boolean

Returns:

  • (Boolean)


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

def include? index
  @relation_hash.key? index
end

#inspect(threshold = 20) ⇒ Object



145
146
147
148
149
150
151
# File 'lib/daru/index/index.rb', line 145

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



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

def key(value)
  return nil unless value.is_a?(Numeric)
  @keys[value]
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



105
106
107
108
109
110
111
112
113
# File 'lib/daru/index/index.rb', line 105

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



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

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

#slice(*args) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/daru/index/index.rb', line 153

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



115
116
117
118
119
120
121
122
123
124
125
# File 'lib/daru/index/index.rb', line 115

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



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

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)


93
94
95
# File 'lib/daru/index/index.rb', line 93

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.



168
169
170
# File 'lib/daru/index/index.rb', line 168

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