我需要一个固定大小的FIFO列表,可以在创建对象时任意设置。一个数组工作,但我厌倦了检查它的大小,并在每次推送一个新值时弹出最旧的元素。我知道有人说子类化Array是一个坏主意,但我仍然想这样做,因为它是我需要的最优雅的解决方案。
到目前为止,这是我的代码。
footer {
width: 100vw;
}
有了这个对象,我可以像这样定义一个25元素的FIFO:
class FIFOList < Array
attr_reader :FIFO_length
attr_writer :FIFO_length
def initialize(l)
super()
@FIFO_length = l
end
def push(element)
super(element)
self.shift if self.length > @FIFO_length
end
并且整天推送元素并且总是拥有最新的25个。只要我一次推送一个元素(a.push()),一切都很好。但是,我希望能够使用数组初始化一个新FIFO,就像使用本机Array对象一样。
a = FIFOList.new(25)
产生5个元素的数组a。但这不是它的工作方式,我不知道该怎么做。这是一个显示问题的IRB会话:
a = [1,2,3,4,5]
因此,静态数组不会被指定为&#34;内容&#34; FIFOL对象,&#34; a&#34;只是成为新静态数组的引用。那不是我想要的行为。从我所做的阅读中看来,似乎我需要在我的FIFOList类中添加方法来覆盖[]和可能的[] =,但我不知道该怎么做。如果这不是正确的方法,我会对#34;加载&#34;感到满意。将数组作为参数并在内部完成魔法的方法,但我不确定如何加载&#34;传递给自我的价值观。有人可以帮忙吗?
答案 0 :(得分:3)
你已经想出了自己的解决方案,但这是我的:
class FIFOList < Array
attr_reader :fifo_length
def initialize(len, arr=[])
arr = arr[-len, len] if arr.size > len
super(arr)
@fifo_length = len
end
def push(*args)
if args.size > fifo_length
return replace(args[-fifo_length, fifo_length])
end
num_to_shift = (size + args.size) - fifo_length
shift(num_to_shift) unless num_to_shift < 0
super(*args)
end
end
a = FIFOList.new(5, ["a1", "a2", "a3"])
p a # => ["a1", "a2", "a3"]
p a.push("b1") # => ["a1", "a2", "a3", "b1"]
p a.push("c1", "c2", "c3") # => ["a3", "b1", "c1", "c2", "c3"]
p a.push("d1", "d2", "d3", "d4", "d5", "d6", "d7") # => ["d3", "d4", "d5", "d6", "d7"]
请注意,构造函数会自动剪切初始数组,如果它太长,FIFOList#push
镜像Array#push
,因为它需要任意数量的参数并始终返回self
(并且正常工作)即使给出了太多的论据)。
虽然有些人会反对猴子修补数组,但你也可以添加一个创建FIFOList的Array#to_fifo
便利方法:
class Array
def to_fifo
FIFOList.new(size, self)
end
end
a = [1,2,3,4,5].to_fifo
p a.class # => FIFOList
您可以在repl.it上查看它:https://repl.it/@jrunning/WillingJoyfulAttributes
答案 1 :(得分:3)
您可以在不继承Array
的情况下执行非常类似的操作,但使用撰写代替:
class FIFOList
attr_reader :size, :arr
def self.[](*values)
obj = self.new(values.size)
obj.arr = values
obj
end
def initialize(size)
@size = size
@arr = Array.new
end
def push(element)
arr.push(element)
arr.shift if arr.length > size
arr
end
end
然后你可以用类似的方式使用它:
a = FIFOList.new(3)
# => #<FIFOList:0x00007ffe87071150 @size=3, @arr=[nil, nil, nil]>
a.push 1
# => [nil, nil, 1]
a.push 2
# => [nil, 1, 2]
a.push 3
# => [1, 2, 3]
a.push 4
# => [2, 3, 4]
a.arr
# => [2, 3, 4]
或者如果您想在不使用push
每个值的情况下使用它:
a = FIFOList[1,2,3]
# => #<FIFOList:0x00007feea9015d70 @size=3, @arr=[1, 2, 3]>
a.push 4
# => [2, 3, 4]
答案 2 :(得分:1)
答案 3 :(得分:0)
我仍然希望我可以直接分配并使其正常工作,但此代码允许我选择初始化。
class FIFOList < Array
attr_reader :FIFO_length
attr_writer :FIFO_length
def initialize(l, init_value = nil)
if init_value != nil && init_value.class.to_s == "Array" && init_value.length <= l then
super(init_value)
@FIFO_length = l
elsif init_value == nil
super()
@FIFO_length = l
else
raise "optional 2nd parameter required to be an Array"
end
end
def push(element)
super(element)
self.shift if self.length > @FIFO_length #truncate the FIFO to the defined length
end
end