如何在Ruby中将人类可读的数字转换为计算机可读的数字?

时间:2014-07-07 21:16:14

标签: ruby arrays

我在Ruby工作,其中包含一系列人类可读格式的数字(例如,2.5B,1.27M,600,000,其中" B"代表数十亿,& #34; M"代表百万)。我试图将数组的所有元素转换为相同的格式。

以下是我写的代码:

array.each do |elem|
    if elem.include? 'B'
        elem.slice! "B"
        elem = elem.to_f
        elem = (elem * 1000000000)
    else if elem.include? 'M'
        elem.slice! "M"
        elem = elem.to_f
        elem = (elem * 1000000)
    end
end

但是,当我使用puts(array)检查数组的元素时,数字会显示为" B"和" M"切掉但是乘法转换似乎没有被应用(例如,数字现在读取2.5,1.27,600,000,而不是2500000000,1270000,600,000)。

我做错了什么?

6 个答案:

答案 0 :(得分:1)

首先要注意的是,ruby中的else ifelsif。见http://www.tutorialspoint.com/ruby/ruby_if_else.htm

这是一个可以尝试的工作函数:

def convert_array_items_from_human_to_integers(array)

    array.each_with_index do |elem,i|
        if elem.include? 'B'
            elem.slice! "B"
            elem = elem.to_f
            elem = (elem * 1000000000)
        elsif elem.include? 'M'
            elem.slice! "M"
            elem = elem.to_f
            elem = (elem * 1000000)
        end
        array[i] = elem
    end

    return array 

end

致电convert_array_items_from_human_to_integers(["2.5B", "1.2M"])

返回[2500000000.0, 1200000.0]

答案 1 :(得分:1)

试试这个:

array.map do |elem|
    elem = elem.gsub('$','')
    if elem.include? 'B'
        elem.to_f * 1000000000
    elsif elem.include? 'M'
        elem.to_f * 1000000
    else
        elem.to_f
    end
end

这使用map代替each来返回新数组。您尝试分配数组元素的副本,保留原始数组(slice!除外,它会在适当位置修改)。您可以首先免除切片,因为to_f将忽略任何非数字字符。

编辑:

如果您有$2.5B等主要字符,正如您的问题标题所示(但不是您的示例),则您需要明确删除这些字符。但是你的示例代码也没有处理,所以我认为这不是问题。

答案 2 :(得分:1)

另一种变化:

array = ['2.5B', '1.27M', '$600000']

p array.each_with_object([]) { |i, a|
  i = i.gsub('$', '')
  a << if i.include? 'B'
    i.to_f * 1E9
  elsif i.include? 'M'
    i.to_f * 1E6
  else
    i.to_f
  end
}

#=> [2500000000.0, 1270000.0, 600000.0]

答案 3 :(得分:0)

在pjs上扩大一点&#39;回答:

array.each do |elem|

elem是一个局部变量,指向每个数组元素,一次一个。当你这样做时:

        elem.slice! "B"

您正在向该数组元素发送一条消息,告诉它切片B.并且您在最终结果中看到了这一点。但是当你这样做时:

        elem = elem.to_f

现在您已将本地变量elem重新分配给全新的内容。您还没有重新分配数组中的内容,只是elem的内容。

答案 4 :(得分:0)

以下是我如何去做的事情:

ARY = %w[2.5B 1.27M 600,000]

def clean_number(s)
  s.gsub(/[^\d.]+/, '')
end


ARY.map{ |v|

  case v
  when /b$/i
    clean_number(v).to_f * 1_000_000_000
  when /m$/i
    clean_number(v).to_f * 1_000_000
  else
    clean_number(v).to_f
  end

}
# => [2500000000.0, 1270000.0, 600000.0]

代码的内容在case语句中。对乘数的简单检查允许我去除不需要的字符并乘以正确的值。

通常我们可以使用to_f来找到像“1.2”这样的字符串相乘的浮点数,但由于“$”,它会因“$ 1.2M”而分解。对于标记数千的嵌入式逗号也是如此:

'$1.2M'.to_f # => 0.0
'1.2M'.to_f # => 1.2
'6,000'.to_f # => 6.0
'6000'.to_f # => 6000.0

要解决仅包含该值的简单字符串的问题,除了使用gsub(/[^\d.]+/, '')剥离不需要的字符之外,没有必要做任何更好的事情:

'$1.2M'.gsub(/[^\d.]+/, '') # => "1.2"
'1.2M'.gsub(/[^\d.]+/, '') # => "1.2"
'6,000'.gsub(/[^\d.]+/, '') # => "6000"
'6000'.gsub(/[^\d.]+/, '') # => "6000"

[^\d.]表示“任何 NOT 数字或'.'

小心如何将十进制值转换为整数。你最终可能会失去重要的精确度:

 '0.2M'.gsub(/[^\d.]+/, '').to_f * 1_000_000 # => 200000.0
 '0.2M'.gsub(/[^\d.]+/, '').to_i * 1_000_000 # => 0
('0.2M'.gsub(/[^\d.]+/, '').to_f * 1_000_000).to_i  # => 200000

当然,如果你的字符串比简单的数字和乘数更复杂,那么这一切都会失效。分解字符串并识别那些子字符串很容易,但这是一个不同的问题。

答案 5 :(得分:0)

我会这样做:

<强>代码

T, M, B = 1_000, 1_000_000, 1_000_000_000

def convert(arr)
  arr.map do |n|
    m = n.gsub(/[^\d.TMB]/,'')
    m.to_f * (m[-1][/[TMB]/] ? Object.const_get(m[-1]) : 1)
  end
end

示例

arr = %w[$2.5B 1.27M 22.5T, 600,000]
convert(arr)    
  # => [2500000000.0, 1270000.0, 22500.0, 600000.0]

<强>解释

该行

m = n.gsub(/[^\d.TMB]/,'')
  # => ["2.5B", "1.27M", "22.5T", "600000"]

只是消除不需要的字符。

  m.to_f * (m[-1][/[TMB]/] ? Object.const_get(m[-1]) : 1)

返回转换为float的字符串的乘积和字符串的最后一个字符给出的常量(如果该字符为TMB,则为{{ 1}}。

实际实施可能是这样的:

1

如果我们希望将1,000的引用从class A T, M, B = 1_000, 1_000_000, 1_000_000_000 def doit(arr) c = self.class.constants.map(&:to_s).join arr.map do |n| m = n.gsub(/[^\d.#{c}]/,'') m.to_f * (m[-1][/[#{c}]/] ? self.class.const_get(m[-1]) : 1) end end end 更改为T并将K添加为万亿,我们只需要更改

T

  T, M, B = 1_000, 1_000_000, 1_000_000_000