Sha256: 33e650c749b271d79013a3889763717c77adee6b637eba536845ec6b8bee3853

Contents?: true

Size: 1.55 KB

Versions: 2

Compression:

Stored size: 1.55 KB

Contents

require "set"

class Lycopodium < Array
  class Error < StandardError; end
  class Collision < Error; end

  attr_accessor :function

  # @param [Array] set a set of values
  # @param [Proc] function a method that transforms a value
  def initialize(set, function = lambda{|value| value})
    replace(set)
    self.function = function
  end

  # @return [Array] the members of the set without collisions
  def reject_collisions
    hashes, collisions = hashes_and_collisions

    items = hashes.reject do |_,hash|
      collisions.include?(hash)
    end.map do |item,_|
      item
    end

    self.class.new(items, function)
  end

  # @return [Hash] a mapping from the original to the transformed value
  # @raise [Collision] if the method creates collisions between members of the set
  def value_to_fingerprint
    hashes, collisions = hashes_and_collisions

    unless collisions.empty?
      message = []
      collisions.each do |collision|
        items = hashes.select do |_,hash|
          hash == collision
        end.map do |item,_|
          item
        end
        message << %(#{items.map(&:inspect) * ", "} => "#{collision}")
      end
      raise Collision, message * "\n"
    end

    hashes
  end

private

  def hashes_and_collisions
    collisions = Set.new

    hashes = {}
    counts = {}

    each do |item|
      unless hashes.key?(item)
        hashes[item] = function.call(item)
      end
      if counts.key?(hashes[item])
        collisions << hashes[item]
      else
        counts[hashes[item]] = 1
      end
    end

    [hashes, collisions]
  end
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
lycopodium-0.0.2 lib/lycopodium.rb
lycopodium-0.0.1 lib/lycopodium.rb