Last active
February 23, 2025 12:54
-
-
Save fwilleke80/55b49cb0c30959aa1b760d5f1110b885 to your computer and use it in GitHub Desktop.
Non-repeating equally distributed random values
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import random | |
| ### @brief Cache dictionary for `get_non_repeating_random_value()` | |
| non_repeating_random_value_cache = { | |
| "available_numbers_storage": {}, | |
| "previous_range_storage": {}, | |
| "previous_number_storage": {} | |
| } | |
| ### @brief Returns a non-repeating random value in the range `min_val .. max_val`. | |
| ### | |
| ### @details | |
| ### The non-repetitiveness is garanted for any range of min/max values, as well as | |
| ### for each key. Use the key to manage multiple non-repeating random sequences in | |
| ### a row. | |
| ### | |
| ### @param str | |
| ### @param min_val | |
| ### @param max_val | |
| ### | |
| ### @return The generated random value | |
| def get_non_repeating_random_value(key: str, min_val: int, max_val: int, cache: dict): | |
| # Unpack caches | |
| available_numbers_storage: dict = cache["available_numbers_storage"] | |
| previous_range_storage: dict = cache["previous_range_storage"] | |
| previous_number_storage: dict = cache["previous_number_storage"] | |
| # Get array of available numbers for this value name | |
| available_numbers: list[int] = available_numbers_storage.get(key, list()) | |
| # Compare current random range to previous random range. | |
| # If they're not equal, re-init the array. | |
| previous_range: tuple[int, int] = previous_range_storage.get(key, None) | |
| if previous_range is not None and (min_val != previous_range[0] or max_val != previous_range[1]): | |
| available_numbers_storage[key] = [] | |
| available_numbers: list[int] = available_numbers_storage[key] | |
| # If the list of available random number is empty, populate it | |
| if not available_numbers: | |
| available_numbers: list[int] = [i for i in range(min_val, max_val + 1)] | |
| available_numbers_storage[key] = available_numbers | |
| # Get previously chosen random number | |
| previous_number: int = previous_number_storage.get(key, None) | |
| # Randomly choose an available number | |
| # Additionally to chosing numbers only from the remaining available numbers, | |
| # we also ensure that it's not the previously chosen number again. This could | |
| # have happened if availableNumber had been re-populated during this call. | |
| while True: | |
| random_number: int = random.choice(available_numbers) | |
| if random_number != previous_number: | |
| break | |
| # Remove the chosen number from array | |
| available_numbers.remove(random_number) | |
| # Memorize previously chosen random number | |
| # This is done to prevent the same number to be chosen again, if the array | |
| # is going to be re-populated in the next call. | |
| previous_number_storage[key]: int = random_number | |
| # Memorize random range | |
| previous_range_storage[key]: list[int, int] = [min_val, max_val] | |
| return random_number | |
| def main(): | |
| # Test range A | |
| for _ in range(20): | |
| print("\n------") | |
| random_number = get_non_repeating_random_value("a", 0, 5, non_repeating_random_value_cache) | |
| print(f"get_non_repeating_random_value(\"a\", 0, 5) = {random_number}") | |
| # Test range A | |
| for _ in range(20): | |
| print("\n------") | |
| random_number = get_non_repeating_random_value("a", 7, 17, non_repeating_random_value_cache) | |
| print(f"get_non_repeating_random_value(\"a\", 7, 17) = {random_number}") | |
| # Test range B | |
| for _ in range(20): | |
| print("\n------") | |
| random_number = get_non_repeating_random_value("b", 10, 15, non_repeating_random_value_cache) | |
| print(f"get_non_repeating_random_value(\"b\", 10, 15) = {random_number}") | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment