Ruby 中的数字运算(需要优化) [英] Number crunching in Ruby (optimisation needed)
问题描述
Ruby 可能不是这方面的最佳语言,但我对在我的终端中使用它感到很舒服,所以这就是我要使用的.
Ruby may not be the optimal language for this but I'm sort of comfortable working with this in my terminal so that's what I'm going with.
我需要处理从 1 到 666666 的数字,所以我将所有包含 6 但不包含 7、8 或 9 的数字标记出来.第一个数字将是 6
,下一个数字将是16
,然后是 26
等等.然后我需要它像这样打印 (6=6) (16=6) (26=6)
并且当我有像 60
到 66的范围时代码> 我需要像
(60 THRU 66=6)
(SPSS 语法)一样打印它.
I need to process the numbers from 1 to 666666 so I pin out all the numbers that contain 6 but doesn't contain 7, 8 or 9. The first number will be 6
, the next 16
, then 26
and so forth.
Then I needed it printed like this (6=6) (16=6) (26=6)
and when I have ranges like 60
to 66
I need it printed like (60 THRU 66=6)
(SPSS syntax).
我有这段代码,它可以工作,但它既不美观也不高效,那么我该如何优化它?
I have this code and it works but it's neither beautiful nor very efficient so how could I optimize it?
(后面可能是傻代码)
class Array
def to_ranges
array = self.compact.uniq.sort
ranges = []
if !array.empty?
# Initialize the left and right endpoints of the range
left, right = array.first, nil
array.each do |obj|
# If the right endpoint is set and obj is not equal to right's successor
# then we need to create a range.
if right && obj != right.succ
ranges << Range.new(left,right)
left = obj
end
right = obj
end
ranges << Range.new(left,right) unless left == right
end
ranges
end
end
write = ""
numbers = (1..666666).to_a
# split each number in an array containing it's ciphers
numbers = numbers.map { |i| i.to_s.split(//) }
# delete the arrays that doesn't contain 6 and the ones that contains 6 but also 8, 7 and 9
numbers = numbers.delete_if { |i| !i.include?('6') }
numbers = numbers.delete_if { |i| i.include?('7') }
numbers = numbers.delete_if { |i| i.include?('8') }
numbers = numbers.delete_if { |i| i.include?('9') }
# join the ciphers back into the original numbers
numbers = numbers.map { |i| i.join }
numbers = numbers.map { |i| i = Integer(i) }
# rangify consecutive numbers
numbers = numbers.to_ranges
# edit the ranges that go from 1..1 into just 1
numbers = numbers.map do |i|
if i.first == i.last
i = i.first
else
i = i
end
end
# string stuff
numbers = numbers.map { |i| i.to_s.gsub(".."," thru ") }
numbers = numbers.map { |i| "(" + i.to_s + "=6)"}
numbers.each { |i| write << " " + i }
File.open('numbers.txt','w') { |f| f.write(write) }
正如我所说,它适用于数以百万计的数字 - 但我想要一些关于如何使数据更漂亮、更高效的建议.
As I said it works for numbers even in the millions - but I'd like some advice on how to make prettier and more efficient.
推荐答案
我删除了我之前对 parlez-vous-ruby? 的尝试并弥补了这一点.我知道有 x3ro 优秀示例的优化版本.
I deleted my earlier attempt to parlez-vous-ruby? and made up for that. I know have an optimized version of x3ro's excellent example.
$,="\n"
puts ["(0=6)", "(6=6)", *(1.."66666".to_i(7)).collect {|i| i.to_s 7}.collect do |s|
s.include?('6')? "(#{s}0 THRU #{s}6=6)" : "(#{s}6=6)"
end ]
与 x3ro 的版本相比
Compared to x3ro's version
它使用了我所有的优化想法
It uses all my ideas for optimization
- 基于 7 位模数的代数(所以基数为 7 数)
- 生成最后一位智能":这是压缩范围的原因
那么……时间是什么时候?这是用 8 位数字进行测试(到 66666666,或 823544 行输出):
So... what are the timings? This was testing with 8 digits (to 66666666, or 823544 lines of output):
$ time ./x3ro.rb > /dev/null
real 8m37.749s
user 8m36.700s
sys 0m0.976s
$ time ./my.rb > /dev/null
real 0m2.535s
user 0m2.460s
sys 0m0.072s
即使性能实际上很好,它甚至不接近C 优化版 我之前发帖说:由于 OutOfMemory,我无法将 my.rb 运行到 6666666666 (6x10).跑到9位数时,这是比较结果:
Even though the performance is actually good, it isn't even close to the C optimized version I posted before: I couldn't run my.rb to 6666666666 (6x10) because of OutOfMemory. When running to 9 digits, this is the comparative result:
sehe@meerkat:/tmp$ time ./my.rb > /dev/null
real 0m21.764s
user 0m21.289s
sys 0m0.476s
sehe@meerkat:/tmp$ time ./t2 > /dev/null
real 0m1.424s
user 0m1.408s
sys 0m0.012s
C 版本仍然快 15 倍......考虑到它在裸机上运行,这是公平的.
The C version is still some 15x faster... which is only fair considering that it runs on the bare metal.
希望你喜欢它,如果只是为了学习 Ruby,我可以请你投票吗:)
Hope you enjoyed it, and can I please have your votes if only for learning Ruby for the purpose :)
(你能说我很自豪吗?这是我第一次接触 ruby;我在 2 小时前开始了 ruby koans...)
编辑@johndouthat:
非常好!base7 的使用非常聪明,这对于您的第一次 ruby 试用来说非常棒:)
Very nice! The use of base7 is very clever and this a great job for your first ruby trial :)
这里对您的代码段稍作修改,可以让您测试 10 多个数字而不会出现 OutOfMemory 错误:
Here's a slight modification of your snippet that will let you test 10+ digits without getting an OutOfMemory error:
puts ["(0=6)", "(6=6)"]
(1.."66666666".to_i(7)).each do |i|
s = i.to_s(7)
puts s.include?('6') ? "(#{s}0 THRU #{s}6=6)" : "(#{s}6=6)"
end
# before:
real 0m26.714s
user 0m23.368s
sys 0m2.865s
# after
real 0m15.894s
user 0m13.258s
sys 0m1.724s
这篇关于Ruby 中的数字运算(需要优化)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!