Class: LexoRanker::Ranker

Inherits:
Object
  • Object
show all
Defined in:
lib/lexoranker/ranker.rb

Overview

LexoRanker is a lexicographic ranking system that uses lexicographic ordering to sort items in a list, rather than numbers.

Defined Under Namespace

Classes: CharacterSpace, CharacterSpaceEncoder

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(character_space = CharacterSpace) ⇒ Object

Returns LexoRanker::Ranker a ranker.

Examples:

Create a new ranker with the default character space

ranker = LexoRanker::Ranker.new

Create a ranker with a custom character space

class CustomCharacterSpace
  CHARACTERS = %w[a b c d e]
  def self.chr(ord)
    CHARACTERS[ord]
  end
  def self.ord(chr)
    CHARACTERS.index(chr)
  end
  def min
    CHARACTERS.first
  end
  def max
    CHARACTERS.last
  end
end

custom_ranker = LexoRanker::Ranker.new(CustomCharacterSpace)


68
69
70
71
# File 'lib/lexoranker/ranker.rb', line 68

def initialize(character_space = CharacterSpace)
  @character_space = character_space
  @encoder = CharacterSpaceEncoder.new(character_space)
end

Instance Attribute Details

#character_spaceObject (readonly)

Returns the current object used as the character space. By default this is the built-in LexoRanker::Ranker::CharacterSpace class, but can be overridden in the constructor



42
43
44
# File 'lib/lexoranker/ranker.rb', line 42

def character_space
  @character_space
end

Instance Method Details

#balanced_ranks(element_count) ⇒ Array

Return an array of rankings in order that cover element_count number of elements.

Examples:

Return an array with 5 elements

list = LexoRanker::Ranker.new.balanced_ranks(5) # ["2", "E", "Q", "c", "o"]

Raises:

  • (ArgumentError)


162
163
164
165
166
167
168
169
170
171
172
# File 'lib/lexoranker/ranker.rb', line 162

def balanced_ranks(element_count)
  raise ArgumentError, "`element_count` must be greater than zero" if element_count.nil? || element_count <= 0

  start = 2
  places = (Math.log(element_count) / Math.log(character_space.size)).ceil
  ending = (character_space.size**places) - 2

  Array.new(element_count).map.with_index do |_, i|
    encoder.encode(start + (i.to_f / element_count.to_f * ending).round).rjust(places, character_space.min)
  end
end

#between(previous, following) ⇒ String

Return a LexoRank between previous and following arguments. Either argument can be called with NilClass to return a LexoRank that is after/before the passed argument, but not necessarily before/after any other particular element.

Passing NilClass as an argument, and then attempting to insert a LexoRank into an existing list may end up with identical LexoRank rankings, which is invalid.

Examples:

Return a LexoRank between previous and following

LexoRanker::Ranker.new.between('M', 'T') # => 'R'

Return a LexoRank anywhere before following

LexoRanker::Ranker.new.between(nil, 'M') # => 'H'


134
135
136
# File 'lib/lexoranker/ranker.rb', line 134

def between(previous, following)
  value_between(before: previous, after: following)
end

#first(first_value) ⇒ String

Return a LexoRank that comes before what would be the first item of a LexoRanked list. If first_item is nil, returns a LexoRank for a list with one element

Examples:

Return a LexoRank before first_value

LexoRanker::Ranker.new.first('M') # => 'H'

Return a LexoRank with a nil first_value

LexoRanker::Ranker.new.first(nil) # => 'M'


97
98
99
# File 'lib/lexoranker/ranker.rb', line 97

def first(first_value)
  value_between(before: character_space.min, after: first_value)
end

#init_from_array(list) ⇒ Hash

Init a new LexoRanking for an already sorted list of elements @todo: Will cause issues with lists that have duplicate elements, either warn or fix.

Examples:

Return a hash with element => LexoRank hash

list = [1,2,3]
LexoRanker::Ranker.new.init_from_array(list) # { 1 => 'M', 2 => 'T', 3 => 'W' }

Raises:

  • (ArgumentError)


148
149
150
151
152
# File 'lib/lexoranker/ranker.rb', line 148

def init_from_array(list)
  raise ArgumentError, "`list` can not be nil" if list.nil?

  list.zip(balanced_ranks(list.size)).to_h
end

#last(last_value) ⇒ String

Return a LexoRank that comes after what would be the last item of a LexoRanked list. If last_item is nil, returns a LexoRank for a list with one element

Examples:

Return a LexoRank after last_value

LexoRanker::Ranker.new.last('M') # => 'T'

Return a Lexorank with a nil last_value

LexoRanker::Ranker.new.last(nil) # => 'M'


113
114
115
# File 'lib/lexoranker/ranker.rb', line 113

def last(last_value)
  value_between(before: last_value, after: character_space.max)
end

#onlyString

Returns a LexoRank at the midpoint between the min and max character space. Used for when you need to rank only one item in a list

Examples:

Return a LexoRank with no previous or following items.

LexoRanker::Ranker.new.only # => 'M'


81
82
83
# File 'lib/lexoranker/ranker.rb', line 81

def only
  value_between(before: character_space.min, after: character_space.max)
end