JavaFree.org | RubyOnBr.org

Sorteio de números em Ruby

Acompanhar Sorteio de números em Ruby 24 posts, 6 participantes

Avatar ArthurGeek 183 posts

Pessoal,

Precisava fazer um scriptzinho que sorteasse 5mil números entre 1000 pessoas. Cada uma teria 5 números pro sorteio.

Ainda nem comecei a escrever, só fiz uns testes rápidos no IRB.
Os números e nomes estão num array, e queria que os dados do sorteio ficassem num hash, parecido com isso:

@x = {"Arthur" => [1, 2, 3, 4, 5], “Matz” => [6, 7, 8, 9, 10]}

Só que eu não consegui iterar pelos valores do array de números e adicionar esses dados no Hash.
O Hash não tem o método <<, nem pussh, nem nada. Como eu faço pra adicionar valores num Hash, dessa forma?

 
Avatar Ronaldo 388 posts

variavel_hash[objeto_indice] = valor

 
Avatar ArthurGeek 183 posts

Mas como eu vou adicionando estes valores assim como o método << faz com arrays?

E testei dessa maneira tb:

Eu sei que eu poderia pegar todos os valores e depois dar um hash[indice] = array mas queria ver se tem como fazer dessa maneira que eu perguntei e entender pq acontece isso com estes códigos que eu passei…

 
Avatar Ronie Uliana 891 posts

Tenta isso daqui:

Esse é um idioma legal do Ruby pra se trabalhar com hashes de array. Se o array não existe dentro do hash ele já cria e associa, se o array existe, ele simplesmente associa.

Não é lá muito legível pra quem não conhece, mas faz bem o trabalho.

 
Avatar ArthurGeek 183 posts

Legal Ronie!

Funcionou!

mas e aê, alguém sabe explicar pq aqueles meus testes retornam um Hash em branco e o outro retorna um valor 16? Agora fiquei curioso!

 
Avatar Ronaldo 388 posts

O código abaixo também funciona tranqüilo sem precisar repetir o ||= [] toda hora.

a = Hash.new([])
a[:arthur] << 2
a[:arthur] << 3

Sobre o código retornar um hash em branco, pelo que eu entendi acontece o seguinte: quando o valor é simples, o método to_s do hash retorna tranqüilo. Se o valor é composto, ele não exibe nada. Compare:

{ 1 => 2 }.to_s
{ 1 => [1, 2] }.to_s

o TaQ, que já investigou bem mais a linguagem provavelmente pode explicar o porquê disse melhor.

Sobre o valor 16, o código executado naquele momento foi 2 << 3 (note que você atribuiu 2 e depois fez << 3). O operador << significa shift left para inteiros. O número passou de (em binário): 00000010 (2) para 00010000 (16).

 
Avatar Ronie Uliana 891 posts

Ronaldo, cuidado com o Hash.new([]). Ele mantém o mesmo array pra todos os elementos do hash criados por default.

O melhor é usar um bloco de código pra obter o mesmo efeito. Eu costumo usar aquele idioma pq normalmente é só uma linha no meio de um loop. Mas tá certo, ele é bem confuso.

 
Avatar Ronaldo 388 posts

Caramba, boa pegada. :-) “Mim ter que aprender muito sobre o Ruby ainda”.

E faz o maior sentido mesmo já que o array fica parametrizado em uma variável de instância pelo visto. O bloco seria a solução mesmo.

Sobre o idioma, acho que realmente é um dos mais comuns do Ruby. Só que se precisar repetir muito fica realmente confuso.

 
Avatar ArthurGeek 183 posts

Vish..
Não seria um bug do método to_s do hash?
Aqui até com valores simples ele deu uns retornos estranhos…

Bom, eu não preciso escrever um hash no scriptzinho que vou fazer, mas que isso tá estranho, tá! (ou o lerdo aqui não entendeu nada..haha)

 
Avatar Ronaldo 388 posts

Cara, mea culpa. Eu coloquei o to_s pensando que ele voltava a mesma coisa que a representação. Olhando a documentação vejo que não volta. E eu estava errado de qualquer forma.

Eu fiz alguns testes aqui e parece que o problema está no uso do default que o Ronie apontou. Veja:

>> a = Hash.new { |hash,key| hash[key] = "" }
=> {}
>> a[:a] << 2
=> "\002"
>> a[:a] << 3
=> "\002\003"
>> a
=> {:a=>"\002\003"}

>> a = Hash.new("")
=> {}
>> a[:a] << 2
=> "\002"
>> a[:a] << 3
=> "\002\003"
>> a
=> {}
 
Avatar TaQ 188 posts

Gente, desculpem a correria, mas estamos com umas situações novas aqui na empresa e bem corridos.
Sobre a distribuição de números e mencionando o Hash.new, olha só:

Fiz meio “nas coxas” aqui mas acho que dá para ver que ele distribui os números para a galera usando umas “magias negras” do Hash.new. Aí é só aumentar o limite das pessoas e do limite numérico. No final tem uma checagem para ver se não houveram números repetidos.

 
Avatar ArthurGeek 183 posts

TaQ vc é O cara! hehe

Valeu!

Eu já tinha desenvolvivo uma soluçãozinha aqui mas nada comparada com essa sua versão! hehe

É por isso que eu gosto do pessoal aqui.. eu pedi ajuda num método e já me passam uma versão do script inteiro funcionando e muito mais “elegante” do que eu tava fazendo.. :)

Isso pq você tá numa correria… :p

 
Avatar Ronie Uliana 891 posts

Mestre Taq Tiuzão Metaleiro!

Nada como arranjar um tiu que manja :)

 
Avatar TaQ 188 posts

Mas que #$#$#$ de #$#%$#$% de tio que é esse. :-)

Sobre essas “magias negras” do Hash.new eu postei um lance interessante aqui, inclusive passei para o Luca que havia feito uma comparação do Fibonacci em Java e Ruby.

Antes de usar o Hash.new eu costumava desenhar um pentagrama no chão, acender umas velas vermelhas e sacrificar um bode para esses lances obscuros. Aí uma vez minha sogra apareceu do nada no meio do pentagrama e eu parei com essas coisa do demo. Agora, só as em código. :-)

 
Eu2 Carlos Eduardo 266 posts

Eu digo, e as pessoas não acreditam, que o Taq é esse cara aqui , ai depois ficam ai chorando as minguas…

 
Avatar Mereghost 835 posts

HUAHUAHUA! Boa Carlos!

TaQ:

A Fibonacci em uma linha fica bem criptica. Parece até formula para conjurar a sogr… digo, o cramulhão. =/

 
Avatar Ronie Uliana 891 posts

Só um detalhe besta:

pode ser escrito:

Tou pra “louse slayer” hoje, heim, tá louco? :p

 
Avatar Ronie Uliana 891 posts

Putz… o TaQ me atiçou :) fiquei brincando aqui um pouco e cheguei nesse programinha

limit = 100
by_user = 5
users = %w[taq ronaldo arthur ronie carlos ghost]

sorted_array = (1..limit).to_a.sort_by { rand } 

result = {}

users.each_with_index do |it, index|
  min = index * by_user
  result[it] = sorted_array[min, by_user]
end

result.each do |key, value|
  puts key + ' - ' + value.join(", ")
end

- Editado: colocado pre pq code bagunçou o coreto -

A única magia negra aí, bem legal, é essa linha:

Ela cria um array de “limit” posições e bagunça o dito :D . Bastou ordenar por rand . Peguei esse truque daqui

Esse code snippets é bem legal!!!!

 
Avatar Ronaldo 388 posts

Falando em atiçar:

def lottery(users, total, per_user)
	(1..total).sort_by(&:rand).inject(Hash[*users.zip([]).flatten]) { |r, i| r.each { |k, v|  r[k] ||= []; r[k] << i and break if r[k].size < per_user }; r }
end

lottery(%w[taq ronaldo arthur ronie carlos], 100, 5).each do |user, values|
  puts user + ": " + values.join(", ")
end

O lance do &:rand depende de você estar usando suporte a isso; assim, melhor testado em um console Rails.

 
Avatar ArthurGeek 183 posts

Vish!
Agora bagunçou tudo…
O código do Ronie eu até consegui entender, mas pra “digerir” esse do Ronaldo ainda tenho que aprender muita coisa de Ruby! hehe

Ronaldo, o que impede, ou é que é preciso, pra ter esse suporte ao &:rand fora do Rails?

 
Avatar Ronaldo 388 posts

É que o suporte a Symbol#to_proc, do qual o &:rand depende, só existe atualmente no Rails (a menos, é claro, que você tenha implementado em suas bibliotecas. A próxima versão do Ruby terá isso por default.

 
Avatar Ronie Uliana 891 posts

Maluuuuucoooo!!!

Preciso estudar mais isso o_O Viajei!!! Mas essa do &:rand é muito legal. Já tinha visto aqui no fórum “de outra feita”, mas tinha esquecido. Muito bom!

 
Avatar TaQ 188 posts

Ou, vai fundir a cuca aí vai. :-)

 
Avatar Ronaldo 388 posts

Um idioma que está me agradando muito no Rails é o tal do “expressão and comando” com if ou unless opcional. Você pode fazer algo como:

redirect_to :controller => "login" and return unless session[:user]

Eu acho que fica super-legível :-)

Sobre o lance acima, eu confesso que abusei do inject. O coitado não foi feito para esse tipo de coisa. Mas a performance é relativamente boa porque nada é transformado duas vezes e os loops são pequenos.