# Documentation: https://github.com/monzita/algorithmix/wiki/Deque module Algorithmix module DataStructure module Generic class Deque # Creates a new deque. # # @param obj [#to_a] # @kwarg copy [true, false] # @return newly created deque # @raise ArgumentError, if given obj doesn't respond to #to_a method def initialize(obj = nil, copy: false) @container = [] obj.nil? ? nil : from_obj(obj, copy) end # Assigns content of an obj, to content of the deque. # # @param obj [#to_a] # @kwarg copy [true, false] by default is set to false, which means that no copy of the object will be made # @raise ArgumentError, if given object doesn't respond to #to_a method # @return self object def assign(obj, copy: false) from_obj(obj, copy) end # Inserts a new element at the beginning of the deque. # # @param value # @return self object def push_front(value) @container.unshift(value) self end # (see #push_front) def >>(value) push_front(value) end # Inserts a new element at the end of the deque. # # @param value # @return self object def push_back(value) @container << value self end # (see #push_back) def <<(value) push_back(value) end # Removes first element of the deque. # # @raise Algorithmix::EmptyContainerError, if the deque is empty. # @return first element of the deque def pop_front raise EmptyContainerError, "The deque is empty." if @container.empty? @container.shift end # Removes last element of the deque. # # @raise Algorithmix::EmptyContainerError, if the deque is empty. # @return last element of the deque def pop_back raise EmptyContainerError, "The deque is empty." if @container.empty? @container.pop end # Returns first element of the deque. def front @container.first end # Returns last element of the deque. def back @container.last end # Checks if the deque is empty. def empty? @container.empty? end # Returns size of the deque. def size @container.size end # (see #size) def length @container.size end # Returns the element at given index. # # @param idx # @return element at given position, or nil if there is no element at that index. def [](idx) @container[idx] end # (see #[]) def at(idx) @container[idx] end # Compares contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [true, false] # @raise ArgumentError, if given object is not a deque def ==(deque) raise ArgumentError, "Undefined method Deque#== for #{deque}:#{deque.class}" unless deque.is_a?(Deque) @container == deque.to_a end # (see #==) def eql?(deque) raise ArgumentError, "Undefined method Deque#eql? for #{deque}:#{deque.class}" unless deque.is_a?(Deque) self == deque end # Compares contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [true, false] # @raise ArgumentError, if given object is not a deque def !=(deque) raise ArgumentError, "Undefined method Deque#!= for #{deque}:#{deque.class}" unless deque.is_a?(Deque) @container != deque.to_a end # (see #!=) def diff?(deque) raise ArgumentError, "Undefined method Deque#diff? for #{deque}:#{deque.class}" unless deque.is_a?(Deque) self != deque end # Compares contents of the deque and a deque given as argument. # # @param deque [Deque] # @return 1, if content of the deque is greater than content of the given deque, # 0, if contents are equal # -1, if content of the second deque is greater than content of self object # @raise ArgumentError, if given object is not a deque def <=>(deque) raise ArgumentError, "Undefined method Deque#<=> for #{deque}:#{deque.class}" unless deque.is_a?(Deque) @container <=> deque.to_a end # Concatenates contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [Deque] a new deque # @raise ArgumentError, if given object is not a deque def +(deque) raise ArgumentError, "Undefined method Deque#+ for #{deque}:#{deque.class}" unless deque.is_a?(Deque) Deque.new(@container + deque.to_a) end # (see #+) def concat(deque) raise ArgumentError, "Undefined method Deque#concat for #{deque}:#{deque.class}" unless deque.is_a?(Deque) self + deque end # (see #+) def merge(deque) raise ArgumentError, "Undefined method Deque#merge for #{deque}:#{deque.class}" unless deque.is_a?(Deque) self + deque end # Concatenates contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [Deque] self object # @raise ArgumentError, if given object is not a deque def concat!(deque) raise ArgumentError, "Undefined method Deque#concat! for #{deque}:#{deque.class}" unless deque.is_a?(Deque) @container += deque.to_a self end # Concatenates contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [Deque] self object # @raise ArgumentError, if given object is not a deque def merge!(deque) raise ArgumentError, "Undefined method Deque#merge! for #{deque}:#{deque.class}" unless deque.is_a?(Deque) @container += deque.to_a self end # Unites contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [Deque] a new deque # @raise ArgumentError, if given object is not a deque def |(deque) raise ArgumentError, "Undefined method Deque#| for #{deque}:#{deque.class}" unless deque.is_a?(Deque) Deque.new(@container | deque.to_a) end # (see #|) def union(deque) raise ArgumentError, "Undefined method Deque#union for #{deque}:#{deque.class}" unless deque.is_a?(Deque) self | deque end # Unites contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [Deque] self object # @raise ArgumentError, if given object is not a deque def union!(deque) raise ArgumentError, "Undefined method Deque#union! for #{deque}:#{deque.class}" unless deque.is_a?(Deque) @container |= deque.to_a self end # Finds intersection of contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [Deque] a new deque # @raise ArgumentError, if given object is not a deque def &(deque) raise ArgumentError, "Undefined method Deque#& for #{deque}:#{deque.class}" unless deque.is_a?(Deque) Deque.new(@container & deque.to_a) end # (see #&) def intersect(deque) raise ArgumentError, "Undefined method Deque#intersect for #{deque}:#{deque.class}" unless deque.is_a?(Deque) self & deque end # Finds intersection of contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [Deque] self object # @raise ArgumentError, if given object is not a deque def intersect!(deque) raise ArgumentError, "Undefined method Deque#intersect! for #{deque}:#{deque.class}" unless deque.is_a?(Deque) @container &= deque.to_a self end # Finds difference of contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [Deque] a new deque # @raise ArgumentError, if given object is not a deque def -(deque) raise ArgumentError, "Undefined method Deque#- for #{deque}:#{deque.class}" unless deque.is_a?(Deque) Deque.new(@container - deque.to_a) end # (see #-) def difference(deque) raise ArgumentError, "Undefined method Deque#difference for #{deque}:#{deque.class}" unless deque.is_a?(Deque) self - deque end # Finds difference of contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [Deque] a new deque # @raise ArgumentError, if given object is not a deque def difference!(deque) raise ArgumentError, "Undefined method Deque#difference! for #{deque}:#{deque.class}" unless deque.is_a?(Deque) @container -= deque.to_a self end # Finds symmetric difference of contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [Deque] a new deque # @raise ArgumentError, if given object is not a deque def ^(deque) raise ArgumentError, "Undefined method Deque#^ for #{deque}:#{deque.class}" unless deque.is_a?(Deque) Deque.new((@container | deque.to_a) - (@container & deque.to_a)) end # (see #symmetric_difference) def symmetric_difference(deque) raise ArgumentError, "Undefined method Deque#symmetric_difference for #{deque}:#{deque.class}" unless deque.is_a?(Deque) self ^ deque end # Finds symmetric difference of contents of the deque and a deque given as argument. # # @param deque [Deque] # @return [Deque] self object # @raise ArgumentError, if given object is not a deque def symmetric_difference!(deque) raise ArgumentError, "Undefined method Deque#symmetric_difference! for #{deque}:#{deque.class}" unless deque.is_a?(Deque) @container = (@container | deque.to_a) - (@container & deque.to_a) self end # Converts content of the deque to an array witl elements. def to_a @container end # Clears content of the deque. # # @return self object def clear @container = [] self end # Filters elements of the deque by given condition. # # @param &block # @return [Deque] a new deque def select(&block) Deque.new( @container.select { |e| block.call(e)}) end # Filters elements of the deque by given condition. # # @param &block # @return [Deque] self 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 deque. # # @param &block # @return [Deque] a new deque def map(&block) Deque.new(@container.map { |e| block.call(e)}) end # Applies a function to each element of the deque. # # @param &block # @return [Deque] self 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