patternrubyModerate
Generating a random alphanumeric string succinctly and efficiently
Viewed 0 times
randomefficientlyalphanumericgeneratingsuccinctlyandstring
Problem
I want to generate a random alphanumeric string in ruby, as succinctly and efficiently as possible. The following solution works, but is obviously not very efficient.
Please review the following code, bearing in mind that I am trying to keep it as succinct and readable as possible while improving efficiency. Be sure to include a detailed explanation in your answer.
Please review the following code, bearing in mind that I am trying to keep it as succinct and readable as possible while improving efficiency. Be sure to include a detailed explanation in your answer.
([nil]*8).map { ((48..57).to_a+(65..90).to_a+(97..122).to_a).sample.chr }.joinSolution
You could use
From the documentation for Array:
new(size=0, obj=nil) new(array) new(size) {|index| block }
Returns a new array. In the first form, the new array is empty. In the second it is created with size copies of obj (that is, size references to the same obj). The third form creates a copy of the array passed as a parameter (the array is generated by calling to_ary on the parameter). In the last form, an array of the given size is created. Each element in this array is calculated by passing the element’s index to the given block and storing the return value.
Perhaps it is better to create the array with the valid characters once in advance:
I made a Benchmark for the solutions.
The result:
@Nat: Gratulation, your version is the fastest ;)
To analyze the fastest way to build the
Result:
Array.new(8){[*'0'..'9', *'a'..'z', *'A'..'Z'].sample}.joinFrom the documentation for Array:
new(size=0, obj=nil) new(array) new(size) {|index| block }
Returns a new array. In the first form, the new array is empty. In the second it is created with size copies of obj (that is, size references to the same obj). The third form creates a copy of the array passed as a parameter (the array is generated by calling to_ary on the parameter). In the last form, an array of the given size is created. Each element in this array is calculated by passing the element’s index to the given block and storing the return value.
Perhaps it is better to create the array with the valid characters once in advance:
range = [*'0'..'9', *'a'..'z', *'A'..'Z']
Array.new(8){range.sample}.joinI made a Benchmark for the solutions.
require 'benchmark'
N = 10_000 #Number of Test loops
Benchmark.bmbm(10) {|b|
b.report('Nat' ) { N.times { ([nil]*8).map { ((48..57).to_a+(65..90).to_a+(97..122).to_a).sample.chr }.join } }
b.report('tokland') { N.times { 8.times.map { [*'0'..'9', *'a'..'z', *'A'..'Z'].sample }.join } }
b.report('knut' ) { N.times { Array.new(8){[*'0'..'9', *'a'..'z', *'A'..'Z'].sample}.join } }
b.report('Natinit') {
range = ((48..57).to_a+(65..90).to_a+(97..122).to_a)
N.times { ([nil]*8).map { range.sample.chr }.join }
}
b.report('knutinit') {
range = ((48..57).to_a+(65..90).to_a+(97..122).to_a)
N.times { Array.new(8){range.sample}.join }
}
} #BenchmarkThe result:
Rehearsal ---------------------------------------------
Nat 0.765000 0.000000 0.765000 ( 0.765625)
tokland 2.172000 0.000000 2.172000 ( 2.171875)
knut 1.953000 0.000000 1.953000 ( 1.984375)
Natinit 0.063000 0.000000 0.063000 ( 0.062500)
knutinit 0.078000 0.000000 0.078000 ( 0.078125)
------------------------------------ total: 5.031000sec
user system total real
Nat 0.781000 0.000000 0.781000 ( 0.781250)
tokland 1.953000 0.000000 1.953000 ( 1.968750)
knut 1.922000 0.000000 1.922000 ( 1.921875)
Natinit 0.063000 0.000000 0.063000 ( 0.062500)
knutinit 0.078000 0.000000 0.078000 ( 0.078125)@Nat: Gratulation, your version is the fastest ;)
To analyze the fastest way to build the
range I used the following benchmark:Benchmark.bmbm(10) {|b|
b.report('Natinit') {
N.times { ((48..57).to_a+(65..90).to_a+(97..122).to_a) }
}
b.report('knutinit') {
N.times { [*'0'..'9', *'a'..'z', *'A'..'Z'] }
}
} #BenchmarkResult:
Rehearsal ---------------------------------------------
Natinit 0.093000 0.000000 0.093000 ( 0.093750)
knutinit 0.250000 0.000000 0.250000 ( 0.250000)
------------------------------------ total: 0.343000sec
user system total real
Natinit 0.094000 0.000000 0.094000 ( 0.093750)
knutinit 0.219000 0.000000 0.219000 ( 0.218750)Code Snippets
Array.new(8){[*'0'..'9', *'a'..'z', *'A'..'Z'].sample}.joinrange = [*'0'..'9', *'a'..'z', *'A'..'Z']
Array.new(8){range.sample}.joinrequire 'benchmark'
N = 10_000 #Number of Test loops
Benchmark.bmbm(10) {|b|
b.report('Nat' ) { N.times { ([nil]*8).map { ((48..57).to_a+(65..90).to_a+(97..122).to_a).sample.chr }.join } }
b.report('tokland') { N.times { 8.times.map { [*'0'..'9', *'a'..'z', *'A'..'Z'].sample }.join } }
b.report('knut' ) { N.times { Array.new(8){[*'0'..'9', *'a'..'z', *'A'..'Z'].sample}.join } }
b.report('Natinit') {
range = ((48..57).to_a+(65..90).to_a+(97..122).to_a)
N.times { ([nil]*8).map { range.sample.chr }.join }
}
b.report('knutinit') {
range = ((48..57).to_a+(65..90).to_a+(97..122).to_a)
N.times { Array.new(8){range.sample}.join }
}
} #BenchmarkRehearsal ---------------------------------------------
Nat 0.765000 0.000000 0.765000 ( 0.765625)
tokland 2.172000 0.000000 2.172000 ( 2.171875)
knut 1.953000 0.000000 1.953000 ( 1.984375)
Natinit 0.063000 0.000000 0.063000 ( 0.062500)
knutinit 0.078000 0.000000 0.078000 ( 0.078125)
------------------------------------ total: 5.031000sec
user system total real
Nat 0.781000 0.000000 0.781000 ( 0.781250)
tokland 1.953000 0.000000 1.953000 ( 1.968750)
knut 1.922000 0.000000 1.922000 ( 1.921875)
Natinit 0.063000 0.000000 0.063000 ( 0.062500)
knutinit 0.078000 0.000000 0.078000 ( 0.078125)Benchmark.bmbm(10) {|b|
b.report('Natinit') {
N.times { ((48..57).to_a+(65..90).to_a+(97..122).to_a) }
}
b.report('knutinit') {
N.times { [*'0'..'9', *'a'..'z', *'A'..'Z'] }
}
} #BenchmarkContext
StackExchange Code Review Q#15958, answer score: 10
Revisions (0)
No revisions yet.