在Ruby中区分十进制数的索引和数组内的整数?

时间:2014-09-23 04:26:04

标签: ruby arrays

由于Ruby进行类型转换,如何正确获取索引?

我希望这返回1

[1,2.0,2,3].index(2.0)
#=> 1

我希望这返回2

[1,2.0,2,3].index(2)
#=> 1

2 个答案:

答案 0 :(得分:5)

将块与eql?一起使用是一种方式:

[1,2.0,2,3].index {|e| e.eql? 2.0}
#=> 1
[1,2.0,2,3].index {|e| e.eql? 2}
#=> 2

==不同,eql?仅在接收者和参数具有相同类型和相等值时才返回true。因此2 == 2.0会返回true2.eql? 2.0会返回false

答案 1 :(得分:1)

数组#index和Equality

您没有得到预期的结果,因为Array#index使用更通用的BasicObject#==代替Object#eql?来比较值,而不使用类型< / em>的参数/值被考虑在内。在鸭子打字语言中,这通常是你想要的。

请考虑以下示例,该示例使用==FloatFixnum进行比较:

2 == 2.0
#=> true

请注意,Ruby认为两个数值相等,尽管它们的类型不同。这是documented behavior。由于Array#index的非块形式将参数为== first 索引返回到索引值,[1,2.0,2,3].index(2.0)[1,2.0,2,3].index(2)都将返回相同的指数。

使用Array#index

的Block Form

所有Ruby方法都接受一个可选块,当Kernel#block_given?为真时,某些核心类的行为会有所不同。 Array #index的文档说:

  

如果给出了一个块...返回该块返回true的第一个对象的索引。如果找不到匹配则返回nil。

区分两种不同类型值的规范方法是使用Array#index的块形式来检查与#eql的对象是否相等?而不是#==。例如:

array = [1,2.0,2,3]
array.index { |i| i.eql? 2   }
array.index { |i| i.eql? 2.0 }

这将返回您期望的值,但需要额外打字。这确实是您问题的首选解决方案。

Monkey-Patch the Array Class

对像Array这样的核心类进行猴子修补通常是一个错误的想法,但你可以通过重新打开Array类并修改Array #index的行为来强制Array #index以你想要的方式运行输入值相等。一种方法是在Module#alias_method的帮助下,并使用Array#old_index的块语法在每次使用数字参数调用Array#index时检查Numeric#eql?

请考虑以下事项:

class Array
  alias_method :old_index, :index
  def index value
    old_index { |i| i.eql? value }
  end
end

[1,2.0,2,3].index 2.0
#=> 1
[1,2.0,2,3].index 2
#=> 2

这可以按照您的预期方式工作,并且您仍然可以在需要原始类型无关的相等性检查时随时使用Array#old_index。但是,请谨慎使用,因为一旦您更改了Array类的正常行为,其他模块或gem可能就不会按预期运行。

很高兴知道你可以这样做,但是用链锯来玩杂耍本身就是一种冒险的活动。您的里程可能会有所不同。