设置计数器、递增和返回的更简洁的方法?
More concise way of setting a counter, incrementing, and returning?
我正在研究一个问题,我想逐个字符地比较两个长度相等的字符串。对于字符不同的每个索引,我需要将计数器加 1。现在我有这个:
def compute(strand1, strand2)
raise ArgumentError, "Sequences are different lengths" unless strand1.length == strand2.length
mutations = 0
strand1.chars.each_with_index { |nucleotide, index| mutations += 1 if nucleotide != strand2[index] }
mutations
end
end
我是这门语言的新手,但这对我来说非常不Ruby。是否有一个单行程序可以合并设置计数器、递增它然后返回它的过程?
我的思路是选择所有不匹配的字符,然后获取结果数组的大小。但是,据我所知,没有 select_with_index
方法。我也在研究 inject
但似乎无法弄清楚我将如何在这种情况下应用它。
inject
确实可以通过一种方式用一条线来做到这一点,所以你在正确的轨道上:
strand1.chars.each_with_index.inject(0) { |count, (nucleotide, index)|
nucleotide == strand2[index] ? count : count + 1 }
我们从初始值 0 开始,然后如果 2 个字母相同,我们只是 return 累加器值的当前值,如果字母不同,我们加 1。
另外,请注意这里调用 each_with_index
时没有阻塞。当这样调用时,它 return 是一个枚举器对象。这让我们可以使用其他枚举器方法之一(在本例中为 inject
),值和索引对 return 由 each_with_index
编辑,允许 each_with_index
和inject
待合并。
编辑:看着它,user12341234's 解决方案是一个很好的方法。好好利用zip
!我可能会同意。
可能最简单的答案就是计算差异:
strand1.chars.zip(strand2.chars).count{|a, b| a != b}
这里有一些单行:
strand1.size.times.select { |index| strand1[index] != strand2[index] }.size
这不是最好的,因为它生成了一个大小为 O(n) 的中间数组。
strand1.size.times.inject(0) { |sum, index| sum += 1 if strand1[index] != strand2[index]; sum }
不占用额外内存,但有点难以阅读。
strand1.chars.each_with_index.count { |x, index| x != strand2[index] }
我会同意的。感谢 user12341234 提到 count
这是构建的基础。
更新
我机器上的基准测试给出了与@CarySwoveland 得到的结果不同的结果:
user system total real
mikej 4.080000 0.320000 4.400000 ( 4.408245)
user12341234 3.790000 0.210000 4.000000 ( 4.003349)
Nik 2.830000 0.170000 3.000000 ( 3.008533)
user system total real
mikej 3.590000 0.020000 3.610000 ( 3.618018)
user12341234 4.040000 0.140000 4.180000 ( 4.183357)
lazy user 4.250000 0.240000 4.490000 ( 4.497161)
Nik 2.790000 0.010000 2.800000 ( 2.808378)
这并不是要指出我的代码具有更好的性能,而是要指出环境在选择任何特定实现方法时起着重要作用。
我 运行 在本机 3.13.0-24-generic #47-Ubuntu SMP x64 上,12 核 i7-3930K 上有足够的内存。
这是一个刚刚扩展的评论,所以请不要赞成票(反对票也可以)。
先生们:发动你们的引擎!
测试题
def random_string(n, selection)
n.times.each_with_object('') { |_,s| s << selection.sample }
end
n = 5_000_000
a = ('a'..'e').to_a
s1 = random_string(n,a)
s2 = random_string(n,a)
基准代码
require 'benchmark'
Benchmark.bm(12) do |x|
x.report('mikej') do
s1.chars.each_with_index.inject(0) {|c,(n,i)| n==s2[i] ? c : c+1}
end
x.report('user12341234') do
s1.chars.zip(s2.chars).count{|a,b| a != b }
end
x.report('lazy user') do
s1.chars.zip(s2.chars).lazy.count{|a,b| a != b }
end
x.report('Nik') do
s1.chars.each_with_index.count { |x,i| x != s2[i] }
end
end
结果
mikej 6.220000 0.430000 6.650000 ( 6.651575)
user12341234 6.600000 0.900000 7.500000 ( 7.504499)
lazy user 7.460000 7.800000 15.260000 ( 15.255265)
Nik 6.140000 3.080000 9.220000 ( 9.225023)
user system total real
mikej 6.190000 0.470000 6.660000 ( 6.662569)
user12341234 6.720000 0.500000 7.220000 ( 7.223716)
lazy user 7.250000 7.110000 14.360000 ( 14.356845)
Nik 5.690000 0.920000 6.610000 ( 6.621889)
[编辑:我添加了 'user12341234' 的 lazy
版本。与 lazy
版本的枚举器的情况一样,在使用的内存量和执行时间之间存在权衡。我跑了几次。这里我报告两个典型的结果。 'mikej' 和 'user12341234' 的差异很小,lazy user
的差异更大,Nik
的差异很大。]
我正在研究一个问题,我想逐个字符地比较两个长度相等的字符串。对于字符不同的每个索引,我需要将计数器加 1。现在我有这个:
def compute(strand1, strand2)
raise ArgumentError, "Sequences are different lengths" unless strand1.length == strand2.length
mutations = 0
strand1.chars.each_with_index { |nucleotide, index| mutations += 1 if nucleotide != strand2[index] }
mutations
end
end
我是这门语言的新手,但这对我来说非常不Ruby。是否有一个单行程序可以合并设置计数器、递增它然后返回它的过程?
我的思路是选择所有不匹配的字符,然后获取结果数组的大小。但是,据我所知,没有 select_with_index
方法。我也在研究 inject
但似乎无法弄清楚我将如何在这种情况下应用它。
inject
确实可以通过一种方式用一条线来做到这一点,所以你在正确的轨道上:
strand1.chars.each_with_index.inject(0) { |count, (nucleotide, index)|
nucleotide == strand2[index] ? count : count + 1 }
我们从初始值 0 开始,然后如果 2 个字母相同,我们只是 return 累加器值的当前值,如果字母不同,我们加 1。
另外,请注意这里调用 each_with_index
时没有阻塞。当这样调用时,它 return 是一个枚举器对象。这让我们可以使用其他枚举器方法之一(在本例中为 inject
),值和索引对 return 由 each_with_index
编辑,允许 each_with_index
和inject
待合并。
编辑:看着它,user12341234's 解决方案是一个很好的方法。好好利用zip
!我可能会同意。
可能最简单的答案就是计算差异:
strand1.chars.zip(strand2.chars).count{|a, b| a != b}
这里有一些单行:
strand1.size.times.select { |index| strand1[index] != strand2[index] }.size
这不是最好的,因为它生成了一个大小为 O(n) 的中间数组。
strand1.size.times.inject(0) { |sum, index| sum += 1 if strand1[index] != strand2[index]; sum }
不占用额外内存,但有点难以阅读。
strand1.chars.each_with_index.count { |x, index| x != strand2[index] }
我会同意的。感谢 user12341234 提到 count
这是构建的基础。
更新
我机器上的基准测试给出了与@CarySwoveland 得到的结果不同的结果:
user system total real
mikej 4.080000 0.320000 4.400000 ( 4.408245)
user12341234 3.790000 0.210000 4.000000 ( 4.003349)
Nik 2.830000 0.170000 3.000000 ( 3.008533)
user system total real
mikej 3.590000 0.020000 3.610000 ( 3.618018)
user12341234 4.040000 0.140000 4.180000 ( 4.183357)
lazy user 4.250000 0.240000 4.490000 ( 4.497161)
Nik 2.790000 0.010000 2.800000 ( 2.808378)
这并不是要指出我的代码具有更好的性能,而是要指出环境在选择任何特定实现方法时起着重要作用。
我 运行 在本机 3.13.0-24-generic #47-Ubuntu SMP x64 上,12 核 i7-3930K 上有足够的内存。
这是一个刚刚扩展的评论,所以请不要赞成票(反对票也可以)。
先生们:发动你们的引擎!
测试题
def random_string(n, selection)
n.times.each_with_object('') { |_,s| s << selection.sample }
end
n = 5_000_000
a = ('a'..'e').to_a
s1 = random_string(n,a)
s2 = random_string(n,a)
基准代码
require 'benchmark'
Benchmark.bm(12) do |x|
x.report('mikej') do
s1.chars.each_with_index.inject(0) {|c,(n,i)| n==s2[i] ? c : c+1}
end
x.report('user12341234') do
s1.chars.zip(s2.chars).count{|a,b| a != b }
end
x.report('lazy user') do
s1.chars.zip(s2.chars).lazy.count{|a,b| a != b }
end
x.report('Nik') do
s1.chars.each_with_index.count { |x,i| x != s2[i] }
end
end
结果
mikej 6.220000 0.430000 6.650000 ( 6.651575)
user12341234 6.600000 0.900000 7.500000 ( 7.504499)
lazy user 7.460000 7.800000 15.260000 ( 15.255265)
Nik 6.140000 3.080000 9.220000 ( 9.225023)
user system total real
mikej 6.190000 0.470000 6.660000 ( 6.662569)
user12341234 6.720000 0.500000 7.220000 ( 7.223716)
lazy user 7.250000 7.110000 14.360000 ( 14.356845)
Nik 5.690000 0.920000 6.610000 ( 6.621889)
[编辑:我添加了 'user12341234' 的 lazy
版本。与 lazy
版本的枚举器的情况一样,在使用的内存量和执行时间之间存在权衡。我跑了几次。这里我报告两个典型的结果。 'mikej' 和 'user12341234' 的差异很小,lazy user
的差异更大,Nik
的差异很大。]