# Documentation: https://github.com/monzita/algorithmix/wiki/Queue module Algorithmix module DataStructure module Generic class Queue # Creates a new queue. # # @param obj [#to_a] Any objects which responds to #to_a method # @kwarg copy [true, false] If is set to true, will duplicate the given object. By default is set to false. # @return [Queue] a newly create queue def initialize(obj = nil, copy: false) @container = [] obj.nil? ? nil : from_obj(obj, copy) end # Assigns content of an object, to stack's content, removing previous elements. # # @param obj [#to_a] Any object which responds to #to_a method. # @kwarg copy [true, false] If is set to true, will duplicate the given object. By default is set to false. # @return self object [Queue] def assign(obj, copy: false) from_obj(obj, copy) end # Inserts a value at the end of the queue. # # @param value # @return [Queue] self object def push(value) @container << value self end # (see #push) def <<(value) push(value) end # Removes the front element of the queue. # # @return front element # @raise Algorithmix::EmptyContainerError if the queue is empty. def pop raise EmptyContainerError, "The queue is empty." if @container.empty? @container.shift end # Returns the front element of the queue, or nil if it's empty. def front @container.first end # Returns number of elements in the queue. def size @container.size end # (see #size) def length @container.size end # Checks if the queue is empty. def empty? @container.empty? end # Compares contents of the self object and that given as argument. # # @param queue [Queue] # @return [true, false] # @raise ArgumentError, if given object is not a queue. def ==(queue) raise ArgumentError, "Undefined method Queue#== for #{queue}:#{queue.class}" unless queue.is_a?(Queue) @container == queue.to_a end # (see #==) def eql?(queue) raise ArgumentError, "Undefined method Queue#eql? for #{queue}:#{queue.class}" unless queue.is_a?(Queue) self == queue end # Compares contents of the self object and that given as argument. # # @param queue [Queue] # @return [true, false] # @raise ArgumentError, if given object is not a queue. def !=(queue) raise ArgumentError, "Undefined method Queue#!= for #{queue}:#{queue.class}" unless queue.is_a?(Queue) @container != queue.to_a end # (see #!=) def diff?(queue) raise ArgumentError, "Undefined method Queue#diff? for #{queue}:#{queue.class}" unless queue.is_a?(Queue) self != queue end # Compares contents of the self object and that given as argument. # # @param queue [Queue] # @return 1, if content of the first queue is greater than content of the second # 0, if contents of both queues are equal # -1, if content of the second queue is greater than content of the first # @raise ArgumentError, if given object is not a queue. def <=>(queue) raise ArgumentError, "Undefined method Queue#<=> for #{queue}:#{queue.class}" unless queue.is_a?(Queue) @container <=> queue.to_a end # Concatenates contents of two queues. # # @param queue [Queue] # @return [Queue] a new queue object def +(queue) raise ArgumentError, "Undefined method Queue#+ for #{queue}:#{queue.class}" unless queue.is_a?(Queue) Queue.new(@container + queue.to_a) end # (see #+) def concat(queue) raise ArgumentError, "Undefined method Queue#concat for #{queue}:#{queue.class}" unless queue.is_a?(Queue) self + queue end # (see #+) def merge(queue) raise ArgumentError, "Undefined method Queue#merge for #{queue}:#{queue.class}" unless queue.is_a?(Queue) self + queue end # Same as #+, but modifies the current object def concat!(queue) raise ArgumentError, "Undefined method Queue#concat! for #{queue}:#{queue.class}" unless queue.is_a?(Queue) @container += queue.to_a self end # Same as #+, but modifies the current object def merge!(queue) raise ArgumentError, "Undefined method Queue#merge! for #{queue}:#{queue.class}" unless queue.is_a?(Queue) @container += queue.to_a self end # Unites contents of the self queue and queue given as argument. # # @param queue [Queue] # @return [Queue] a new queue # @raise ArgumentError, if given object is not a queue def |(queue) raise ArgumentError, "Undefined method Queue#| for #{queue}:#{queue.class}" unless queue.is_a?(Queue) Queue.new(@container | queue.to_a) end # (see #|) def union(queue) raise ArgumentError, "Undefined method Queue#union for #{queue}:#{queue.class}" unless queue.is_a?(Queue) self | queue end # Same as #union, but modifies the current object def union!(queue) raise ArgumentError, "Undefined method Queue#union! for #{queue}:#{queue.class}" unless queue.is_a?(Queue) @container |= queue.to_a self end # Finds the intersection of the self object and queue given as argument. # # @param queue [Queue] # @return [Queue] a new queue # @raise ArgumentError, if given object is not a queue def &(queue) raise ArgumentError, "Undefined method Queue#& for #{queue}:#{queue.class}" unless queue.is_a?(Queue) Queue.new(@container & queue.to_a) end # (see #&) def intersect(queue) raise ArgumentError, "Undefined method Queue#intersect for #{queue}:#{queue.class}" unless queue.is_a?(Queue) self & queue end # Same as #&, but modifies the current object. def intersect!(queue) raise ArgumentError, "Undefined method Queue#intersect! for #{queue}:#{queue.class}" unless queue.is_a?(Queue) @container &= queue.to_a self end # Finds the difference of the current queue and queue given as argument. # # @param queue [Queue] # @return [Queue] a new queue # @raise ArgumentError, if given object is not a queue def -(queue) raise ArgumentError, "Undefined method Queue#- for #{queue}:#{queue.class}" unless queue.is_a?(Queue) Queue.new(@container - queue.to_a) end # (see #-) def difference(queue) raise ArgumentError, "Undefined method Queue#difference for #{queue}:#{queue.class}" unless queue.is_a?(Queue) self - queue end # Same as #-, but modifies the current queue. def difference!(queue) raise ArgumentError, "Undefined method Queue#difference! for #{queue}:#{queue.class}" unless queue.is_a?(Queue) @container -= queue.to_a self end # Finds the symmetric difference of the self object and queue given as argument. # # @param queue [Queue] # @return [Queue] a new queue # @raise ArgumentError, if given object is not a queue def ^(queue) raise ArgumentError, "Undefined method Queue#^ for #{queue}:#{queue.class}" unless queue.is_a?(Queue) Queue.new((@container | queue.to_a) - (@container & queue.to_a)) end # (see #^) def symmetric_difference(queue) raise ArgumentError, "Undefined method Queue#symmetric_difference for #{queue}:#{queue.class}" unless queue.is_a?(Queue) self ^ queue end # Same as #^, but modifies the current object. def symmetric_difference!(queue) raise ArgumentError, "Undefined method Queue#symmetric_difference! for #{queue}:#{queue.class}" unless queue.is_a?(Queue) @container = (@container | queue.to_a) - (@container & queue.to_a) end # Converts the queue to an array with elements. def to_a @container end # Clears content of the queue. def clear @container = [] self end # Filters elements of the queue by given condition. # # @param &block # @return [Queue] a new queue def select(&block) Queue.new(@container.select { |e| block.call(e) }) end # Same as #select, but modofies the current object. def select!(&block) @container.select! { |e| block.call(e) } self end # (see #select) def filter(&block) select(&block) end # (see #select!) def filter!(&block) select!(&block) end # (see #select) def find_all(&block) select(&block) end # (see #select!) def find_all!(&block) select!(&block) end # Applies a function to each element of the queue. # # @param &block # @return [Queue] a new queue def map(&block) Queue.new(@container.map { |e| block.call(e)}) end # Same as #map, but modifies the current object. def map!(&block) @container.map! { |e| block.call(e) } self end # (see #map) def apply(&block) map(&block) end # (see #map!) def apply!(&block) map!(&block) end private def from_obj(obj, copy) raise ArgumentError, "Object doesn't respond to #to_a method" unless obj.respond_to?(:to_a) @container = copy ? obj.send(:to_a).dup : obj.send(:to_a) self end end end end end