如何在 Ruby 中递归传递未知 Proc
How to pass unknown Proc recursively in Ruby
问题
我正在尝试编写一个方法 (Array#bubble_sort),它接受一个可选的 proc 参数。
当给定过程时,该方法应根据过程对数组进行排序。
当没有给出 proc 时,该方法应按递增顺序对数组进行排序。
递归地,这在不添加 proc 的情况下工作正常,但是当给定一个未知的 proc 时,我找不到将它作为参数正确传递回来的方法。
代码
class Array
def bubble_sort(&prc)
prc = Proc.new{|a,b| a <=> b} if !prc
self.each_with_index do |ele,idx|
if prc.call(self[idx],self[idx+1]) == 1
self[idx],self[idx+1] = self[idx+1], self[idx]
self.bubble_sort(&prc)
end
end
self
end
end
测试代码
[4, 12, 2, 8, 1, 14, 9, 25, 24, 81].bubble_sort
returns[1, 2, 4, 8, 9, 12, 14, 24, 25, 81]
的预期结果
[4, 12, 2, 8, 1, 14, 9, 25, 24, 81].bubble_sort { |a, b| a.to_s <=> b.to_s }
returns 堆栈级别太深错误而不是 [1, 12, 14, 2, 24, 25, 4, 8, 81, 9]
的预期结果
问题不在于您传递过程,而是 <=>
在数字和字符串上的工作方式不同。
当循环到达数组末尾时,self.idx
等于 self.length - 1
,self.idx + 1
等于 self.length
。由于零索引,在数组上调用 self[self.length]
将始终为 nil。
所以,你最终调用了 proc.call(<last element of array>, nil)
宇宙飞船操作员的行为会有所不同,具体取决于您是 number <=> nil
还是 number.to_s <=> nil.to_s
(这是您比较的两个过程之间的区别):
81 <=> nil
# => nil
81.to_s <=> nil.to_s
# => 1
在你的例子中,你不希望与 nil 的任何比较导致交换,所以你有两个选择:
如果第二个元素为nil,可以将proc改为return nil
:
arr.bubble_sort do |a,b|
b.nil? ? nil : a.to_s <=> b.to_s
end
如果 b
超出范围,您可以完全跳过比较:
self.each_with_index do |ele,idx|
next if idx + 1 == self.length
# ... other stuff
问题
我正在尝试编写一个方法 (Array#bubble_sort),它接受一个可选的 proc 参数。
当给定过程时,该方法应根据过程对数组进行排序。
当没有给出 proc 时,该方法应按递增顺序对数组进行排序。
递归地,这在不添加 proc 的情况下工作正常,但是当给定一个未知的 proc 时,我找不到将它作为参数正确传递回来的方法。
代码
class Array
def bubble_sort(&prc)
prc = Proc.new{|a,b| a <=> b} if !prc
self.each_with_index do |ele,idx|
if prc.call(self[idx],self[idx+1]) == 1
self[idx],self[idx+1] = self[idx+1], self[idx]
self.bubble_sort(&prc)
end
end
self
end
end
测试代码
[4, 12, 2, 8, 1, 14, 9, 25, 24, 81].bubble_sort
returns[1, 2, 4, 8, 9, 12, 14, 24, 25, 81]
[4, 12, 2, 8, 1, 14, 9, 25, 24, 81].bubble_sort { |a, b| a.to_s <=> b.to_s }
returns 堆栈级别太深错误而不是 [1, 12, 14, 2, 24, 25, 4, 8, 81, 9]
问题不在于您传递过程,而是 <=>
在数字和字符串上的工作方式不同。
当循环到达数组末尾时,self.idx
等于 self.length - 1
,self.idx + 1
等于 self.length
。由于零索引,在数组上调用 self[self.length]
将始终为 nil。
所以,你最终调用了 proc.call(<last element of array>, nil)
宇宙飞船操作员的行为会有所不同,具体取决于您是 number <=> nil
还是 number.to_s <=> nil.to_s
(这是您比较的两个过程之间的区别):
81 <=> nil
# => nil
81.to_s <=> nil.to_s
# => 1
在你的例子中,你不希望与 nil 的任何比较导致交换,所以你有两个选择:
如果第二个元素为nil,可以将proc改为return
nil
:arr.bubble_sort do |a,b| b.nil? ? nil : a.to_s <=> b.to_s end
如果
b
超出范围,您可以完全跳过比较:self.each_with_index do |ele,idx| next if idx + 1 == self.length # ... other stuff