3 votes

Ruby - Choisir un élément dans un tableau avec 50% de chance pour a[0], 25% de chance pour a[1]

Rien de très compliqué, en fait je veux juste choisir un élément du tableau comme si je faisais des tirages à pile ou face pour chaque indice et que je choisissais l'indice lorsque j'obtiens une tête. De même, sans tête, je choisis le dernier emplacement.

J'ai trouvé la solution suivante et je me demandais s'il existait un moyen plus efficace de le faire.

def coin_toss(size)
  random_number = rand(2**size)
  if random_number == 0
    return size-1
  else
    return (0..size-1).detect { |n| random_number[n] == 1 }
  end
end

7voto

cHao Points 42294

Première supposition... choisissez un nombre aléatoire entre 1 et 2. 2**size trouver le logarithme de base 2 de cette valeur, et choisir le nombre d'éléments à partir de la fin.

Pardonnez mes horribles compétences en rubis.

return a[-((Math.log(rand(2**size-1)+1) / Math.log(2)).floor) - 1]

si rand renvoie 0, le dernier élément doit être choisi. 1 ou 2, l'avant-dernier. 3, 4, 5 ou 6, le troisième en partant de la fin. Etc. En supposant une distribution égale des nombres aléatoires, chaque élément a deux fois plus de chances d'être choisi que celui qui le suit.

Edit : En fait, il semble qu'il y ait une log2 de sorte que nous n'avons pas à faire le truc de log/log(2).

return a[-(Math.log2(rand(2**size - 1)+1).floor) - 1]

Vous pouvez peut-être vous débarrasser complètement de ces appels de journal comme

return a[-((rand(2**size-1)+1).to_s(2).length)]

Mais vous créez un supplément String . Je ne sais pas si c'est mieux que des mathématiques compliquées :)

Edit : En fait, si vous optez pour la méthode des chaînes, vous pouvez vous débarrasser complètement des +1 et -1. Cela rendrait les probabilités plus précises, puisque les deux derniers éléments devraient avoir une chance égale d'être choisis. (Si l'avant-dernière valeur n'est pas choisie, la dernière valeur le serait toujours).

Edit : Nous pourrions également transformer le ** en un décalage de bits, ce qui devrait être un peu plus rapide (à moins que Ruby ne soit assez intelligent pour le faire déjà).

return a[-(rand(1<<size).to_s(2).length)]

5voto

steenslag Points 29662

Une façon simple et non intelligente est :

def coin_toss( arr )
  arr.detect{ rand(2) == 0 } || arr.last
end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X