将比较运算符作为参数传递给Ruby中的方法的最佳方法是什么?我想创建一个通用排序?数组的识别器,并将'< ='或'> ='传递给此方法。
到目前为止,我有这段代码:
class Array
def sorted?
return 1 if sorted_increasing?
return -1 if sorted_decreasing?
0
end
def sorted_increasing?
return true if length < 2
self[0] <= self[1] && self.drop(1).sorted_increasing?
end
def sorted_decreasing?
return true if length < 2
self[0] >= self[1] && self.drop(1).sorted_decreasing?
end
end
- 似乎有一个sorted_generic?(comparison_operator)方法而不是sorted_increasing会更好?和sorted_decreasing?。
更新:感谢您的回复,我的解决方案如下:
class Array
def sorted?
return 1 if sorted_generic?(:<=)
return -1 if sorted_generic?(:>=)
0
end
def sorted_generic?(comparison)
return true if length < 2
self[0].send(comparison, self[1]) &&
self.drop(1).sorted_generic?(comparison)
end
end
答案 0 :(得分:4)
比较运算符只是Ruby中的方法,所以你可以这样做:
1 <= 2 # is the same as
1.<=(2)
这意味着您可以像其他任何公共方法一样public_send
:
1.public_send(:<=, 2)
答案 1 :(得分:3)
虽然不是对你问题的直接回应,但我建议采用不同的方法。
class Array
def sorted?(direction)
sorted = self.sort
case direction
when :increasing
self == sorted ? 1 : 0
when :decreasing
self == sorted.reverse ? -1 : 0
else
# <raise exception>
end
end
end
[1,2,3,4].sorted?(:increasing) #=> 1
[4,3,2,1].sorted?(:increasing) #=> 0
[1,3,2,4].sorted?(:increasing) #=> 0
[1,1,1,1].sorted?(:increasing) #=> 1
[1,2,3,4].sorted?(:decreasing) #=> 0
[4,3,2,1].sorted?(:decreasing) #=> -1
[1,3,2,4].sorted?(:decreasing) #=> 0
[1,1,1,1].sorted?(:decreasing) #=> -1
另一种方法是使用Enumerable#each_cons。
class Array
def sorted?(op)
each_cons(2).all? { |e,f| e.public_send(op, f) } ? (op == :<= ? 1 : -1) : 0
end
end
[1,2,3,4].sorted?(:<=) #=> 1
[4,3,2,1].sorted?(:<=) #=> 0
[1,3,2,4].sorted?(:<=) #=> 0
[1,1,1,1].sorted?(:<=) #=> 1
[1,2,3,4].sorted?(:>=) #=> 0
[4,3,2,1].sorted?(:>=) #=> -1
[1,3,2,4].sorted?(:>=) #=> 0
[1,1,1,1].sorted?(:>=) #=> -1
答案 2 :(得分:1)
正如@CarySwoveland所说:
您也可以使用Enumerable
方法#each_cons
和#all?
但是,我会更进一步,以允许默认和自定义sorted?
机制。
class Array
def sorted?(sym=:<=,&block)
block ||= ->(a,b){ a.public_send(sym,b) }
each_cons(2).all?(&block)
end
end
这样,您就可以灵活地调用sorted?
并使用预期的increasing
订单,传递类似于reduce
或inject
的符号进行基本比较或传递一个块确定排序对你意味着什么。
这不会在进程中创建任何中间Array
,也不会在第一次失败时产生短路。
这现在不再限制您进行基本操作,例如
array_of_hashes = [{n:9,a:1},{n:14,a:-3},{n:11, a:0}]
array_of_hashes.sorted?
#=> false
array_of_hashes.sorted? do |a,b|
a.values.reduce(:+) <= b.values.reduce(:+)
end
#=> true
此外,您可以添加一些快捷方式,如
class Array
def sorted_increasing?
sorted?(:<=)
end
def sorted_decreasing?
sorted?(:>=)
end
end
这样
a = [1,2,3,4]
a.sorted? == a.sorted_increasing?
#=> true