Ruby - выбор элемента в массиве с вероятностью 50% для [0], 25% для [1] - PullRequest
3 голосов
/ 14 мая 2011

Ничего сложного, в основном я просто хочу выбрать элемент из массива, как будто я делаю броски монет для каждого индекса и выбираю индекс, когда я впервые получаю голову. Кроме того, отсутствие головок означает, что я выбрал последнюю корзину.

Я придумал следующее и подумал, есть ли лучший / более эффективный способ сделать это.

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

Ответы [ 2 ]

7 голосов
/ 15 мая 2011

Первое предположение ... выберите случайное число от 1 до 2**size, найдите базу лога 2 этого и выберите число, которое много элементов в конце.

Прости мой ужасный рубиновый скиллз.

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

, если rand возвращает 0, должен быть выбран последний элемент.1 или 2, следующий за последним.3, 4, 5 или 6, третий с конца.И т. Д. Предполагая равномерное распределение случайных чисел, каждый элемент имеет в два раза больше шансов быть выбранным, чем один после него.

Редактировать: На самом деле, похоже, есть функция log2, поэтому мы ненужно сделать log / log (2).

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

Вы можете вообще избавиться от этих вызовов журнала, как

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

Но вы создаете дополнительныйString.Не уверен, что это лучше, чем сложная математика.:)

Редактировать: На самом деле, если вы собираетесь идти по струнному маршруту, вы можете полностью избавиться от +1 и -1.Это сделало бы вероятности более точными, поскольку последние два элемента должны иметь равные шансы быть выбранными.(Если предпоследнее значение не выбрано, последнее значение всегда будет.)

Редактировать: Мы также можем превратить ** в битовый сдвиг, который должен быть немного быстрее (если Руби не был достаточно умен, чтобы сделать это уже).

return a[-(rand(1<<size).to_s(2).length)]
5 голосов
/ 15 мая 2011

Неумный, простой способ:

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