假设我想取一个数字并将其数字作为数组返回Ruby中 对于这个特定目的或者字符串函数和数字函数一般来说哪个更快?
这些是我认为最常用的算法:
使用字符串:n.to_s.split(//).map {|x| x.to_i}
使用数字:
array = []
until n = 0
m = n % 10
array.unshift(m)
n /= 10
end
答案 0 :(得分:8)
差异似乎小于一个数量级,Fixnum
s的基于整数的方法更快。对于Bignum
s,相对性能开始或多或少均匀,随着数字位数的增长,字符串方法显着胜出。
#!/usr/bin/env ruby
require 'profile'
$n = 1234567890
10000.times do
$n.to_s.split(//).map {|x| x.to_i}
end
% cumulative self self total
time seconds seconds calls ms/call ms/call name
55.64 0.74 0.74 10000 0.07 0.10 Array#map
21.05 1.02 0.28 100000 0.00 0.00 String#to_i
10.53 1.16 0.14 1 140.00 1330.00 Integer#times
7.52 1.26 0.10 10000 0.01 0.01 String#split
5.26 1.33 0.07 10000 0.01 0.01 Fixnum#to_s
0.00 1.33 0.00 1 0.00 1330.00 #toplevel
#!/usr/bin/env ruby
require 'profile'
$n = 1234567890
10000.times do
array = []
n = $n
until n == 0
m = n%10
array.unshift(m)
n /= 10
end
array
end
% cumulative self self total
time seconds seconds calls ms/call ms/call name
70.64 0.77 0.77 1 770.00 1090.00 Integer#times
29.36 1.09 0.32 100000 0.00 0.00 Array#unshift
0.00 1.09 0.00 1 0.00 1090.00 #toplevel
该模式似乎也适用于较小的数字。对于$n = 12345
,基于字符串的方法大约为800ms,基于整数的方法大约为550ms。
当我越过边界进入Bignum
s时,比如$n = 12345678901234567890
,我得到2375毫秒的两种方法。看起来差别很大,我可能会认为内部本地供电Bignum
是字符串式的。但是,documentation似乎暗示了其他原因。
出于学术目的,我再次将位数加倍$n = 1234567890123456789012345678901234567890
。我得到了大约4450ms的字符串方法和9850ms的整数方法,这是一个明显的逆转,排除了我以前的假设。
Number of digits | String program | Integer program | Difference
---------------------------------------------------------------------------
5 | 800ms | 550ms | Integer wins by 250ms
10 | 1330ms | 1090ms | Integer wins by 240ms
20 | 2375ms | 2375ms | Tie
40 | 4450ms | 9850ms | String wins by 4400ms
答案 1 :(得分:7)
使用我在下面提供的数字方法最快。使用num.to_s.each_char.map(&:to_i)
也很快(也更容易)。
使用num.to_s.each_char.map(&:to_i)
最快。
如果速度老实说是您使用的代码(意为don't be evil)的决定因素,那么此代码是作业的最佳选择。< / p>
class Integer
def digits
working_int, digits = self, Array.new
until working_int.zero?
digits.unshift working_int % 10
working_int /= 10
end
digits
end
end
class Bignum
def digits
to_s.each_char.map(&:to_i)
end
end
Here是我考虑得出这个结论的方法。
答案 2 :(得分:1)
我使用Steven Xu的代码示例和String#each_byte-version为'benchmark'做了一个解决方案。
require 'benchmark'
MAX = 10_000
#Solution based on http://stackoverflow.com/questions/6445496/how-much-slower-are-strings-containing-numbers-compared-to-numbers/6447254#6447254
class Integer
def digits
working_int, digits = self, Array.new
until working_int.zero?
digits.unshift working_int % 10
working_int /= 10
end
digits
end
end
class Bignum
def digits
to_s.each_char.map(&:to_i)
end
end
[
12345,
1234567890,
12345678901234567890,
1234567890123456789012345678901234567890,
].each{|num|
puts "========="
puts "Benchmark #{num}"
Benchmark.bm do|b|
b.report("Integer% ") do
MAX.times {
array = []
n = num
until n == 0
m = n%10
array.unshift(m)
n /= 10
end
array
}
end
b.report("Integer% << ") do
MAX.times {
array = []
n = num
until n == 0
m = n%10
array << m
n /= 10
end
array.reverse
}
end
b.report("Integer#divmod ") do
MAX.times {
array = []
n = num
until n == 0
n, x = *n.divmod(10)
array.unshift(x)
end
array
}
end
b.report("Integer#divmod<<") do
MAX.times {
array = []
n = num
until n == 0
n, x = *n.divmod(10)
array << x
end
array.reverse
}
end
b.report("String+split// ") do
MAX.times { num.to_s.split(//).map {|x| x.to_i} }
end
b.report("String#each_byte") do
MAX.times { num.to_s.each_byte.map{|x| x.chr } }
end
b.report("String#each_char") do
MAX.times { num.to_s.each_char.map{|x| x.to_i } }
end
#http://stackoverflow.com/questions/6445496/how-much-slower-are-strings-containing-numbers-compared-to-numbers/6447254#6447254
b.report("Num#digit ") do
MAX.times { num.to_s.each_char.map{|x| x.to_i } }
end
end
}
我的结果:
Benchmark 12345
user system total real
Integer% 0.015000 0.000000 0.015000 ( 0.015625)
Integer% << 0.016000 0.000000 0.016000 ( 0.015625)
Integer#divmod 0.047000 0.000000 0.047000 ( 0.046875)
Integer#divmod<< 0.031000 0.000000 0.031000 ( 0.031250)
String+split// 0.109000 0.000000 0.109000 ( 0.109375)
String#each_byte 0.047000 0.000000 0.047000 ( 0.046875)
String#each_char 0.047000 0.000000 0.047000 ( 0.046875)
Num#digit 0.047000 0.000000 0.047000 ( 0.046875)
=========
Benchmark 1234567890
user system total real
Integer% 0.047000 0.000000 0.047000 ( 0.046875)
Integer% << 0.046000 0.000000 0.046000 ( 0.046875)
Integer#divmod 0.063000 0.000000 0.063000 ( 0.062500)
Integer#divmod<< 0.062000 0.000000 0.062000 ( 0.062500)
String+split// 0.188000 0.000000 0.188000 ( 0.187500)
String#each_byte 0.063000 0.000000 0.063000 ( 0.062500)
String#each_char 0.093000 0.000000 0.093000 ( 0.093750)
Num#digit 0.079000 0.000000 0.079000 ( 0.078125)
=========
Benchmark 12345678901234567890
user system total real
Integer% 0.234000 0.000000 0.234000 ( 0.234375)
Integer% << 0.234000 0.000000 0.234000 ( 0.234375)
Integer#divmod 0.203000 0.000000 0.203000 ( 0.203125)
Integer#divmod<< 0.172000 0.000000 0.172000 ( 0.171875)
String+split// 0.266000 0.000000 0.266000 ( 0.265625)
String#each_byte 0.125000 0.000000 0.125000 ( 0.125000)
String#each_char 0.141000 0.000000 0.141000 ( 0.140625)
Num#digit 0.141000 0.000000 0.141000 ( 0.140625)
=========
Benchmark 1234567890123456789012345678901234567890
user system total real
Integer% 0.718000 0.000000 0.718000 ( 0.718750)
Integer% << 0.657000 0.000000 0.657000 ( 0.656250)
Integer#divmod 0.562000 0.000000 0.562000 ( 0.562500)
Integer#divmod<< 0.485000 0.000000 0.485000 ( 0.484375)
String+split// 0.500000 0.000000 0.500000 ( 0.500000)
String#each_byte 0.218000 0.000000 0.218000 ( 0.218750)
String#each_char 0.282000 0.000000 0.282000 ( 0.281250)
Num#digit 0.265000 0.000000 0.265000 ( 0.265625)
String#each_byte / each_char分割速度越快,对于数字越小,整数版本越快。