红宝石的范围可以从Float开始吗?

时间:2017-04-03 16:56:24

标签: ruby

我是红宝石的初学者,试图用它来帮助我分析生物数据。我需要尝试将一组数据(数组中的数字)与具有特定特征的另一个数据匹配(例如数字+/- 0.25) 我已经提出这个(到目前为止)将一个数据集更改为范围而不是数字:

def range(arr)
  c = []
  arr.each do |b|
    b = (b-0.25..b+0.25)
    b = b.to_a
    c << b
  end
  c = c.flatten
  return c
end

代码提供了所需的数组,但我总是得到

TypeError: can't iterate from Float.

我该如何解决?

背景

这是我的实际数据样本:

  

119.0456 119.0714 119.0721 119.0737 120.0772 130.0746 131.0737 136.0721 140.0951 143.0697 154.038 154.0744 154.1108 155.0949 156.054 169.053 170.1422 171.0646 171.0686 174.0644 174.0795 180.0539 182.1059

我需要将它与理论集相匹配,我需要生成容差为0.002我正在逐步编写代码以生成我的理论集,因为我还不熟悉编码,并且只是想知道如何在我的理论集合周围创建一个+/- 0.002的范围,以使其与实际匹配。

4 个答案:

答案 0 :(得分:9)

  

ruby​​的范围是否以Float开头?

是的,您可以使用浮点数创建范围:

r = 0.25..0.75
#=> 0.25..0.75

但是您无法使用Range#each来遍历它,因为each依赖succ(例如Integer#succ)而Float没有&#39} ; t实现该方法。

相反,您可以使用Range#step并使用explcit增量值:

r.step(0.1) { |f| puts f }

输出:

0.25
0.35
0.45
0.55
0.65
0.75

只是为了好玩,让我们看看如果我们使用Float#next_float会发生什么:

class Float
  alias succ next_float
end

r = 0.25..0.75

r.each { |f| puts f }

输出:

0.25
0.25000000000000006
0.2500000000000001
0.25000000000000017
0.2500000000000002
0.2500000000000003
0.25000000000000033
0.2500000000000004
0.25000000000000044
0.2500000000000005
0.25000000000000056
0.2500000000000006
...
  

代码提供了所需的数组,但我总是得到

TypeError: can't iterate from Float.
     

我该如何解决?

您可以构建一个范围数组:

def range(arr)
  arr.map { |b| b-0.25..b+0.25 }
end

range [1, 2, 3]
#=> [0.75..1.25, 1.75..2.25, 2.75..3.25]

答案 1 :(得分:1)

如果我已正确理解您的问题,您可以这样做:

arr1 = [1,2,3]
arr2 = [1.25, 1.85, 4.25]
s = 0.25

arr1.zip(arr2).select { |a, b| (a-b).abs <= s }
#=> [[1, 1.25], [2, 1.85]]

关键方法Array#zipArray#selectFloat#abs

答案 2 :(得分:1)

首先,这段代码:

def range(arr)
  c = []
  arr.each do |b|
    b = (b-0.25..b+0.25)
    c << b
  end
  return c
end

基本上采用数组并创建一个新数组,每个项目都根据规则进行修改。在Ruby中,您可以将.map()用于此目的:

def range(arr)
  arr.map { |b| (b-0.25..b+0.25) }
end

其次,正如其他人所说,浮点数的范围存在,但是你不能迭代一系列的浮点数,因为Ruby无法知道你想要什么增量。范围(1.0 .. 2.0)在技术上拥有无限数量的数字(例如1.2324123和1.9232311),因此您无法说明每个步骤应该有多大。你可以这样做:

range.step(0.1) { |f| #do stuff with f }

但如果你的目标是比较数组,看看[1,2,3]是否适合[0.75..1.25,1.75..2.25,2.75..3.25]的范围,你就不应该完全迭代范围。您应该使用.cover?()方法来查看数字是否在范围内:

def in_range(arr, ranges)
  return false unless arr.size == ranges.size
  arr.zip(ranges).do { |a, r| return false unless r.cover? a }
  return true
end

答案 3 :(得分:-1)

您没有为范围方法显示结束end - 显示的end会关闭arr.each循环。

这可能是问题吗?