Losowanie szóstki “Chybił trafił” (albo jak kto woli “Chybił nie trafił”)
temp = Array 1..49
tab = Array.new
6.times {tab << temp.delete_at(rand(temp.length))}
puts tab
Czy ktoś ma lepszy pomysł ??
Losowanie szóstki “Chybił trafił” (albo jak kto woli “Chybił nie trafił”)
temp = Array 1..49
tab = Array.new
6.times {tab << temp.delete_at(rand(temp.length))}
puts tab
Czy ktoś ma lepszy pomysł ??
Taki sobie oneliner.
(1..49).sort{rand()-0.5}.first(6)
Teraz robię taką symulację. Przeprowadzam losowanie dopóki nie trafię piątki (szóstki nawet nie próbuję bo się nie doczekam)
[code]def losuj2
(1…49).sort{rand()-0.5}.first(6)
end
def losuj
temp = Array 1…49
tab = Array.new
6.times {tab << temp.delete_at(rand(temp.length))}
tab
end
i=0
begin
i+=1
t1 = losuj
t2 = losuj
end while (t1 & t2).length != 5
puts “Trafiono za #{i} razem”[/code]
funkcja losuj2 działa z oczywistych powodów wolniej.
Może ktoś teraz znajdzie bardziej optymalny sposób na tą symulację.
[quote=Dulo]Taki sobie oneliner.
(1..49).sort{rand()-0.5}.first(6)
[/quote]
Akapit “Just one more thing”
[quote=RORMaster]Losowanie szóstki “Chybił trafił” (albo jak kto woli “Chybił nie trafił”)
temp = Array 1..49
tab = Array.new
6.times {tab << temp.delete_at(rand(temp.length))}
puts tab
Czy ktoś ma lepszy pomysł ??[/quote]
Jeśli kluczowa nie jest dla Ciebie mega wydajność to od ruby 1.8.7 wzwyż możesz:
(1..49).to_a.shuffle.first(6)
Twój sposób, ubrany w odpowiednią metodę, jak dla mnie jest bardzo dobry, z małą poprawką (bardziej idiomatyczny ruby):
arr = (1..49).to_a
puts 6.times.map { arr.delete_at(rand(arr.length)) }
[code]require ‘active_support/all’
a = (1…49).to_a
my_numbers = a.sample(6)
i=0
begin
i+=1
lotto = a.sample(6)
common = my_numbers & lotto
end while common.size < 5 # common.size != 5
puts “Trafiono za #{i} razem”[/code]
I czy warto użyć Set ?:
[code]require ‘active_support/all’
require ‘set’
Benchmark.bm() do |x|
x.report(“set”) do
a = (1..49).to_a
my_numbers = a.sample(6).to_set
100_000.times do
lotto = a.sample(6).to_set
common = my_numbers & lotto
common.size
end
end
x.report(“ary”) do
a = (1…49).to_a
my_numbers = a.sample(6)
100_000.times do
lotto = a.sample(6)
common = my_numbers & lotto
common.size
end
end
end
user system total real
set 2.180000 0.010000 2.190000 ( 2.236029)
ary 0.440000 0.000000 0.440000 ( 0.453888)[/code]
Kod `sample’ można sobie obejrzeć pod :
$GEM_HOME/gems/activesupport-3.0.0/lib/active_support/core_ext/array/random_access.rb
random_access.rb
...
n.times do |i|
r = i + Kernel.rand(size - i)
result[i], result[r] = result[r], result[i]
end
...
Już bardziej optymalnie chyba nie będzie
[quote=paneq]I czy warto użyć Set ?:
[code]require ‘active_support/all’
require ‘set’
Benchmark.bm() do |x|
x.report(“set”) do
a = (1..49).to_a
my_numbers = a.sample(6).to_set
100_000.times do
lotto = a.sample(6).to_set
common = my_numbers & lotto
common.size
end
end
x.report(“ary”) do
a = (1…49).to_a
my_numbers = a.sample(6)
100_000.times do
lotto = a.sample(6)
common = my_numbers & lotto
common.size
end
end
end
user system total real
set 2.180000 0.010000 2.190000 ( 2.236029)
ary 0.440000 0.000000 0.440000 ( 0.453888)[/code]
[/quote]
Bardzo zdziwił mnie ten wynik swego czasu, ale stwierdziłem, że darowanemu benchmarkowi nie zagląda się w zęby
Natomiast postanowiłem to sprawdzić przy innej okazji, i wyszło na jaw, że set (zgodnie z intuicją) działa bardzo szybko dla & oraz |. Problem z wydajnością leży gdzie indziej - w zamianie tablicy na set.
[code=ruby]require ‘set’
require ‘benchmark’
SIZE = 100_000_000
a = []
SIZE.times{|i| a << rand(SIZE/1000)}
a1 = a[0…SIZE/2]
a2 = a[SIZE/2…-1]
s1 = Set.new(a1)
s1.class
s2 = Set.new(a2)
s2.class
Benchmark.bm() do |x|
x.report(“set &”) do
r = s1 & s2
r.size
end
x.report(“set |”) do
r = s1 | s2
r.size
end
x.report(“array &”) do
r = a1 & a2
r.size
end
x.report(“array |”) do
r = a1 | a2
r.size
end
end[/code]
user system total real
set & 0.160000 0.000000 0.160000 ( 0.162904)
set | 0.110000 0.000000 0.110000 ( 0.116595)
array & 14.620000 0.010000 14.630000 ( 14.638718)
array | 28.630000 0.010000 28.640000 ( 28.656151)
Jak się robi benchmark, to warto wiedzieć co się benchmarkuje 8)
Jesteś pewien że Set działa szybciej dla & i | czy może po prostu s1 i s2 jest o kilka rzędów mniejsze?
Fakt, dzięki za zwrócenie uwagi na ten istotny szczegół. Przy kodzie zmienionym w sposób następujący:
SIZE = 10_000_000
a = []
SIZE.times{|i| a << rand(SIZE*1000)}
dostaję następujące wyniki
user system total real
set & 8.620000 0.010000 8.630000 ( 8.634206)
set | 15.360000 0.360000 15.720000 ( 15.716081)
array & 15.780000 0.050000 15.830000 ( 15.825336)
array | 20.980000 0.050000 21.030000 ( 21.018857)
rozmiary zbiorów są następujące
4998720
4998786
czyli zalewie o kilka promili mniejsze niż rozmiary tablic.
Ale wniosek dla obu przypadków jest ten sam - jeśli robimy operacje na zbiorach (w szczególności jeśli wiele elementów może się powtórzyć), to używanie Set jest jak najbardziej uzasadnione.
Z lenistwa nie sprawdziłem sam Ciekawe że dla & różnica jest nadal bardzo duża. Wieczorem sprawdze z czego może wynikać ta zależność.