############################################################################ # # File: weighted.icn # # Subject: Procedure to shuffle list with randomness # # Author: Erik Eid # # Date: May 23, 1994 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # WeightedShuffle returns the list "sample" with only a portion of the # elements switched. Examples: # # L := WeightedShuffle (X, 100) - returns a fully shuffled list # L := WeightedShuffle (X, 50) - every other element is eligible to # be switched # L := WeightedShuffle (X, 25) - every fourth element is shuffled # L := WeightedShuffle (X, 0) - nothing is changed # # The procedure will fail if the given percentage is not between 0 and # 100, inclusive, or if it is not a numeric value. # ############################################################################ procedure WeightedShuffle (sample, percentage) local lcv, pairs, weight, size, newlist, legal, illegal numeric(percentage) | fail (0 <= percentage <= 100) | fail newlist := copy(sample) # Start with a copy of the # original list. size := *newlist legal := list() # This list will hold which # indices are valid choices for # the shuffle, amounting to the # selected percentage of all # elements. # There are two very similar methods used here. I found that using only the # first one created some odd values for 50 < percentage < 100, so I mirrored # the technique to create a list of "bad" indices instead of a list of # "good" indices that the random switch can choose from. if ((percentage <= 50) | (percentage = 100)) then { pairs := integer (size * percentage / 100) # Number of pairs to be switched. if pairs > 0 then { # Makes sure to avoid division by # zero- occurs when there is no # need to shuffle. weight := integer ((real(size) / pairs) + 0.5) # Holds increment used in # selective shuffling, rounded up. lcv := 1 until lcv > size do { put (legal, lcv) # These indices may be used in # the shuffle. lcv +:= weight } } } else { # percentage > 50 pairs := integer (size * (100 - percentage) / 100) # Avoid switching this many pairs. if pairs > 0 then { weight := integer (size / pairs) # Increment, rounded down. illegal := set ([]) # Which indices can't be used? lcv := 1 until lcv > size do { illegal ++:= set([lcv]) # Compile the list of invaild # indices. lcv +:= weight } every lcv := 1 to size do # Whatever isn't bad is good. if not member (illegal, lcv) then put (legal, lcv) } } every newlist[!legal] :=: newlist[?legal] # Shuffle elements only from # legal indices. return newlist end