6

Currently I do something like this to set a variable to a random item in an array:

array=("foo" "bar" "baz")

var=${array[$RANDOM % ${#array[@]} ]}

How would I do if I want to set $var to one of these values, but specify the chance that the variable will be set to the value of each item respectively? Say I want a 73,3% chance for foo, 26,6% chance for bar, and 0,1% chance for baz.

  • Are you allowed to use only bash builtins and no external programs? – Mark Plotnick Feb 4 at 17:30
  • @MarkPlotnick I would prefer bash, but anything that I can run from the command line works – DisplayName Feb 4 at 17:34
6

One way: set up a parallel array with the corresponding percentage chances; below, I've scaled them to 1000. Then, choose a random number between 1 and 1000 and iterate through the array until you've run out of chances:

#!/bin/bash

array=( "foo"  "bar" "baz")
chances=(733    266     1)

choice=$((1 + (RANDOM % 1000)))
value=

for((index=0; index < ${#array[@]}; index++))
do
  choice=$((choice - ${chances[index]}))
  if [[ choice -le 0 ]]
  then
    value=${array[index]}
    break
  fi
done

[[ index -eq ${#array[@]} ]] && value=${array[index]}
printf '%s\n' "$value"
  • I've also used this method before. It works well. However: it might be worth to calculate the sum dynamically. If it's not actually 1000, you get the wrong results. Also, if RANDOM is limited to 32768, there might be some random bias in the selection. – frostschutz Feb 4 at 17:56
  • Great points, frostschutz; I didn't do any error-checking of the sums, since I assumed they were all assigned manually. – Jeff Schaller Feb 4 at 17:59
6

The shell can't do floating point math, but if we just move the decimal point, we can use $RANDOM and integer math:

#!/usr/local/bin/bash
array=("foo" "bar" "baz")
dieroll=$(($RANDOM % 1000))

if [[ "$dieroll" -lt 1 ]]; then
  printf "%s\n" "${array[2]}"
elif [[ "$dieroll" -lt 266 ]]; then
  printf "%s\n" "${array[1]}"
else
  printf "%s\n" "${array[0]}"
fi

This has the advantages of not having to blow the array up to 1000 entries or needing any for loops.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.