Class: Xqsr3::Containers::FrequencyMap
- Inherits:
-
Object
- Object
- Xqsr3::Containers::FrequencyMap
- Includes:
- Enumerable, Diagnostics::InspectBuilder
- Defined in:
- lib/xqsr3/containers/frequency_map.rb
Overview
Hash-like class that counts, as the map’s values, the frequencies of elements, as the map’s keys
Constant Summary collapse
- ByElement =
Class that provides a Hash[]-like syntax as follows:
fm = FrequencyMap::ByElement[ 'abc', 'def', 'abc', :x, 'x', :y ] fm.empty? # => false fm.size # => 5 fm.count # => 6 fm['abc'] # => 2 fm['def'] # => 1 fm['ghi'] # => 0 fm['x'] # => 1 fm['y'] # => 0 fm['z'] # => 0 fm[:x] # => 1 fm[:y] # => 1 fm[:z] # => 0 Class.new do def self.[] *args fm = FrequencyMap.new args.each { |el| fm << el } fm end private_class_method :new end
Class Method Summary collapse
-
.[](*args) ⇒ Object
Creates an instance from the given arguments.
Instance Method Summary collapse
-
#<<(key) ⇒ Object
Pushes an element into the map, assigning it an initial count of 1.
-
#==(rhs) ⇒ Object
Compares the instance for equality against
rhs. -
#[](key) ⇒ Object
Obtains the count for a given key, or
nilif the key does not exist. -
#[]=(key, count) ⇒ Object
Assigns a key and a count.
-
#assoc(key) ⇒ Object
Searches the instance comparing each element with
key, returning the count if found, ornilif not. -
#clear ⇒ Object
Removes all elements from the instance.
-
#count ⇒ Object
The total number of instances recorded.
-
#default ⇒ Object
Obtains the default value of the instance, which will always be
nil. -
#delete(key) ⇒ Object
Deletes the element with the given
keyand its counts. -
#dup ⇒ Object
Duplicates the instance.
-
#each ⇒ Object
(also: #each_pair)
Calls block once for each element in the instance, passing the element and its frequency as parameters.
-
#each_by_frequency ⇒ Object
Enumerates each entry pair - element + frequency - in descending order of frequency.
-
#each_by_key ⇒ Object
Enumerates each entry pair - element + frequency - in key order.
-
#each_key ⇒ Object
Calls block once for each element in the instance, passing the element.
-
#each_value ⇒ Object
Calls block once for each element in the instance, passing the count.
-
#empty? ⇒ Boolean
Returns
trueif instance contains no elements;falseotherwise. -
#eql?(rhs) ⇒ Boolean
Returns
trueifrhsis an instance ofFrequencyMapand contains the same elements and their counts;falseotherwise. -
#fetch(key, default = nil, &block) ⇒ Object
Returns the count from the instance for the given element
key. -
#flatten ⇒ Object
Returns the equivalent flattened form of the instance.
-
#has_key?(key) ⇒ Boolean
(also: #include?, #key?, #member?)
Returns
trueif an element with the givenkeyis in the map;falseotherwise. -
#has_value?(value) ⇒ Boolean
Returns
trueif an element with a count of the givenvalueis in the map;falseotherwise. -
#hash ⇒ Object
A hash-code for this instance.
-
#initialize ⇒ FrequencyMap
constructor
Initialises an instance.
-
#inspect ⇒ Object
A diagnostics string form of the instance.
-
#key(count) ⇒ Object
Returns the element that has the given count, or
nilif none found. -
#keys ⇒ Object
An array of the elements only.
-
#length ⇒ Object
(also: #size)
The number of elements in the map.
-
#merge(fm) ⇒ Object
Returns a new instance containing a merging of the current instance and the
fminstance. -
#merge!(fm) ⇒ Object
Merges the contents of
fminto the current instance. -
#push(key, count = 1) ⇒ Object
Pushes the
elementandcount. - #shift ⇒ Object
-
#store(key, count) ⇒ Object
Causes an element with the given
keyandcountto be stored. -
#to_a ⇒ Object
Converts instance to an array of [key,value] pairs.
-
#to_h ⇒ Object
Obtains reference to internal hash instance (which must not be modified).
-
#to_hash ⇒ Object
Obtains equivalent hash to instance.
- #to_s ⇒ Object
- #values ⇒ Object
Methods included from Diagnostics::InspectBuilder
Methods included from Enumerable
#collect_with_index, #detect_map, #unique
Constructor Details
#initialize ⇒ FrequencyMap
Initialises an instance
157 158 159 160 161 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 157 def initialize @elements = {} @count = 0 end |
Class Method Details
.[](*args) ⇒ Object
Creates an instance from the given arguments
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 93 def self.[] *args return self.new if 0 == args.length if 1 == args.length arg = args[0] case arg when ::NilClass return self.new when ::Hash fm = self.new arg.each do |k, v| fm.store k, v end return fm when ::Array # accepted forms: # # 1. Empty array # 2. Array exclusively of two-element arrays # 3. Array of even number of elements and at every odd index is an integer # 1. Empty array return self.new if arg.empty? # 2. Array exclusively of two-element arrays if arg.all? { |el| ::Array === el && 2 == el.size } return self.[](::Hash.[]([ *arg ])) end # 3. Array of even number of elements and at every odd index is an integer if (0 == (arg.size % 2)) && arg.each_with_index.select { |el, index| 1 == (index % 2) }.map(&:first).all? { |el| el.kind_of? ::Integer } return self.[](::Hash.[](*arg)) end raise ArgumentError, "array parameter not in an accepted form for subscript initialisation" else return self.[] arg.to_hash if arg.respond_to? :to_hash raise TypeError, "given argument is neither a #{::Hash} nor an #{::Array} and does not respond to the to_hash method" end else # treat all other argument permutations as having passed in an array return self.[] [ *args ] end end |
Instance Method Details
#<<(key) ⇒ Object
Pushes an element into the map, assigning it an initial count of 1
-
Parameters:
key-
The element to insert
167 168 169 170 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 167 def << key push key, 1 end |
#==(rhs) ⇒ Object
Compares the instance for equality against rhs
-
Parameters:
-
rhs(nil,::Hash,FrequencyMap) The instance to compare against
-
-
Exceptions:
-
::TypeErrorifrhsis not of the required type(s)
-
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 179 def == rhs case rhs when ::NilClass return false when ::Hash return rhs.size == @elements.size && rhs == @elements when self.class return rhs.count == self.count && rhs == @elements else raise TypeError, "can compare #{self.class} only to instances of #{self.class} and #{::Hash}, but #{rhs.class} given" end false end |
#[](key) ⇒ Object
Obtains the count for a given key, or nil if the key does not exist
-
Parameters:
-
keyThe key to lookup
-
199 200 201 202 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 199 def [] key @elements[key] || 0 end |
#[]=(key, count) ⇒ Object
Assigns a key and a count
-
Parameters:
-
keyThe key to lookup -
count(::Integer) The count to lookup
-
-
Exceptions:
-
::TypeErrorifcountis not an::Integer
-
212 213 214 215 216 217 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 212 def []= key, count raise TypeError, "'count' parameter must be of type #{::Integer}, but was of type #{count.class}" unless Integer === count store key, count end |
#assoc(key) ⇒ Object
Searches the instance comparing each element with key, returning the count if found, or nil if not
221 222 223 224 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 221 def assoc key @elements.assoc key end |
#clear ⇒ Object
Removes all elements from the instance
227 228 229 230 231 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 227 def clear @elements.clear @count = 0 end |
#count ⇒ Object
The total number of instances recorded
234 235 236 237 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 234 def count @count end |
#default ⇒ Object
Obtains the default value of the instance, which will always be nil
240 241 242 243 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 240 def default @elements.default end |
#delete(key) ⇒ Object
Deletes the element with the given key and its counts
-
Parameters:
-
keyThe key to delete
-
249 250 251 252 253 254 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 249 def delete key key_count = @elements.delete key @count -= key_count if key_count end |
#dup ⇒ Object
Duplicates the instance
257 258 259 260 261 262 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 257 def dup fm = self.class.new fm.merge! self end |
#each ⇒ Object Also known as: each_pair
Calls block once for each element in the instance, passing the element and its frequency as parameters. If no block is provided, an enumerator is returned
267 268 269 270 271 272 273 274 275 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 267 def each return @elements.each unless block_given? @elements.each do |k, v| yield k, v end end |
#each_by_frequency ⇒ Object
Enumerates each entry pair - element + frequency - in descending order of frequency
Note: this method is expensive, as it must create a new dictionary and map all entries into it in order to achieve the ordering
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 294 def each_by_frequency tm = {} @elements.each do |element, frequency| tm[frequency] = [] unless tm.has_key?(frequency) tm[frequency].push element end keys = tm.keys.sort.reverse keys.each do |frequency| elements = tm[frequency].sort elements.each do |element| yield element, frequency end end end |
#each_by_key ⇒ Object
Enumerates each entry pair - element + frequency - in key order
Note: this method is more expensive than each because an array of keys must be created and sorted from which enumeration is directed
281 282 283 284 285 286 287 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 281 def each_by_key @elements.keys.sort.each do |key| yield key, @elements[key] end end |
#each_key ⇒ Object
Calls block once for each element in the instance, passing the element. If no block is provided, an enumerator is returned
317 318 319 320 321 322 323 324 325 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 317 def each_key return @elements.each_key unless block_given? keys.each do |element| yield element end end |
#each_value ⇒ Object
Calls block once for each element in the instance, passing the count. If no block is provided, an enumerator is returned
331 332 333 334 335 336 337 338 339 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 331 def each_value return @elements.each_value unless block_given? keys.each do |element| yield @elements[element] end end |
#empty? ⇒ Boolean
Returns true if instance contains no elements; false otherwise
342 343 344 345 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 342 def empty? 0 == size end |
#eql?(rhs) ⇒ Boolean
Returns true if rhs is an instance of FrequencyMap and contains the same elements and their counts; false otherwise
349 350 351 352 353 354 355 356 357 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 349 def eql? rhs case rhs when self.class return self == rhs else return false end end |
#fetch(key, default = nil, &block) ⇒ Object
Returns the count from the instance for the given element key. If key cannot be found, there are several options: with no other arguments, it will raise a ::KeyError exception; if default is given, then that will be returned; if the optional code block is specified, then that will be run and its result returned
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 364 def fetch key, default = nil, &block case default when ::NilClass, ::Integer ; else raise TypeError, "default parameter ('#{default}') must be of type #{::Integer}, but was of type #{default.class}" end unless @elements.has_key? key return default unless default.nil? if block_given? case block.arity when 0 return yield when 1 return yield key else raise ArgumentError, "given block must take a single parameter - #{block.arity} given" end end raise KeyError, "given key '#{key}' (#{key.class}) does not exist" end @elements[key] end |
#flatten ⇒ Object
Returns the equivalent flattened form of the instance
396 397 398 399 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 396 def flatten @elements.flatten end |
#has_key?(key) ⇒ Boolean Also known as: include?, key?, member?
Returns true if an element with the given key is in the map; false otherwise
403 404 405 406 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 403 def has_key? key @elements.has_key? key end |
#has_value?(value) ⇒ Boolean
Returns true if an element with a count of the given value is in the map; false otherwise
410 411 412 413 414 415 416 417 418 419 420 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 410 def has_value? value case value when ::NilClass, ::Integer ; else raise TypeError, "parameter ('#{value}') must be of type #{::Integer}, but was of type #{value.class}" end @elements.has_value? value end |
#hash ⇒ Object
A hash-code for this instance
423 424 425 426 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 423 def hash @elements.hash end |
#inspect ⇒ Object
A diagnostics string form of the instance
431 432 433 434 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 431 def inspect make_inspect show_fields: true end |
#key(count) ⇒ Object
Returns the element that has the given count, or nil if none found
-
Parameters:
-
count(::Integer) The count to lookup
-
-
Exceptions:
-
::TypeErrorifcountis not of the required type(s)
-
448 449 450 451 452 453 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 448 def key count raise TypeError, "'count' parameter must be of type #{::Integer}, but was of type #{count.class}" unless Integer === count @elements.key count end |
#keys ⇒ Object
An array of the elements only
458 459 460 461 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 458 def keys @elements.keys end |
#length ⇒ Object Also known as: size
The number of elements in the map
464 465 466 467 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 464 def length @elements.length end |
#merge(fm) ⇒ Object
Returns a new instance containing a merging of the current instance and the fm instance
NOTE: where any element is found in both merging instances the count will be a combination of the two counts
476 477 478 479 480 481 482 483 484 485 486 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 476 def merge fm raise TypeError, "parameter must be an instance of type #{self.class}" unless fm.instance_of? self.class fm_new = self.class.new fm_new.merge! self fm_new.merge! fm fm_new end |
#merge!(fm) ⇒ Object
Merges the contents of fm into the current instance
NOTE: where any element is found in both merging instances the count will be a combination of the two counts
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 492 def merge! fm fm.each do |k, v| if not @elements.has_key? k @elements[k] = v else @elements[k] += v end @count += v end self end |
#push(key, count = 1) ⇒ Object
Pushes the element and count. If the element already exists, count will be added to the existing count; otherwise it will be count
Signature
-
Parameters:
-
keyThe element key -
count(Integer) The count by which to adjust
-
Exceptions
- +::RangeError+ raised if the value of +count+ results in a negative count for the given element
- +::TypeError+ if +count+ is not an +::Integer+
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 522 def push key, count = 1 raise TypeError, "'count' parameter must be of type #{::Integer}, but was of type #{count.class}" unless Integer === count initial_count = @elements[key] || 0 resulting_count = initial_count + count raise RangeError, "count for element '#{key}' cannot be made negative" if resulting_count < 0 if 0 == resulting_count @elements.delete key else @elements[key] = resulting_count end @count += count self end |
#shift ⇒ Object
543 544 545 546 547 548 549 550 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 543 def shift r = @elements.shift @count -= r[1] if ::Array === r r end |
#store(key, count) ⇒ Object
Causes an element with the given key and count to be stored. If an element with the given key already exists, its count will be adjusted, as will the total count
Return
+true+ if the element was inserted; +false+ if the element was
overwritten
561 562 563 564 565 566 567 568 569 570 571 572 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 561 def store key, count raise TypeError, "'count' parameter must be of type #{::Integer}, but was of type #{count.class}" unless Integer === count old_count = @elements[key] || 0 @elements.store key, count @count += count - old_count old_count == 0 end |
#to_a ⇒ Object
Converts instance to an array of [key,value] pairs
575 576 577 578 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 575 def to_a @elements.to_a end |
#to_h ⇒ Object
Obtains reference to internal hash instance (which must not be modified)
581 582 583 584 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 581 def to_h @elements.to_h end |
#to_hash ⇒ Object
Obtains equivalent hash to instance
587 588 589 590 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 587 def to_hash @elements.to_hash end |
#to_s ⇒ Object
592 593 594 595 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 592 def to_s @elements.to_s end |
#values ⇒ Object
597 598 599 600 |
# File 'lib/xqsr3/containers/frequency_map.rb', line 597 def values @elements.values end |