我在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)。
我做错了什么?
答案 0 :(得分:1)
首先要注意的是,ruby中的else if
是elsif
。见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的字符串的乘积和字符串的最后一个字符给出的常量(如果该字符为T
,M
或B
,则为{{ 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