Skip to main content
added 245 characters in body
Source Link
Ethan Bierlein
  • 15.9k
  • 4
  • 60
  • 146

I've designed a class ObjectPicker, thanObjectPicker that can be given Objectsobjects and weights. Objects can be picked randomly out of the ObjectPickerObjectPicker, with heavier weighted objects having a higher chance of being selected.

The pick() method is designed to be recursive and provide O(logN)\$O(\log n)\$ speed. What I'm not sure about is the defaulting that's currently in place. I'm wondering if there is a better way to handle it. However, I would appreciate any feedback you are willing to provide beyond the specific.

class ObjectPicker:
    """
    An object that stores other objects with weights, and is able to
    pick out one stored object, with a higher chance for higher weighted
    objects.
    """

    def __init__(self):
        """
        Initialize the Object Picker object. Create the instance variable
        bucket for storing objects.
        """
        self.bucket = []

    def add(self, item, weight=1):
        """
        Add an item to the bucket, with given weight.
        :param item: Object to be stored.
        :param weight: Weight given to the object to determine odds.
        """
        if self.bucket:  # If there is anything in the bucket.
            total = self.bucket[-1][-1]  # Get the end number of the last item.
        else:  # If the bucket is empty.
            total = 0  # End number is 0.

        # Object stored in Tuple.
        # (Object, Weight, Starting Num, Ending Num)
        self.bucket.append((item, weight, total, total + weight))

    def pick(self, choice=-1, storage=None):
        """
        Pick an object from the bucket recursively,
        taking weight into account.
        :param choice: Number of choice.
        :param storage: Storage Object to choose from.
        """
        if not storage:  # If no storage is given.
            if not self.bucket:  # If bucket is empty.
                return None  # Return None.
            else:
                storage = self.bucket  # Storage is bucket
                total = storage[-1][-1]  # Get final weight.

        if choice < 0:  # If choice is < 0,
            # Randomly choose a number to represent the choice.
            choice = random.random() * total

        # Start binary search in middle of storage object.
        index = len(storage) // 2
        start, end = storage[index][2:]

        # If the choice is lower, recursively search left half.
        if choice < start:
            return self.pick(choice, storage[:index])
        # If the choice is higher, recursively search right half.
        elif choice > end:
            return self.pick(choice, storage[index + 1:])
        # Otherwise, choice is in number spread and return object.
        else:
            return storage[index][0]

I've designed a class ObjectPicker, than can be given Objects and weights. Objects can be picked randomly out of the ObjectPicker, with heavier weighted objects having a higher chance of being selected.

The pick() method is designed to be recursive and provide O(logN) speed. What I'm not sure about is the defaulting that's currently in place. I'm wondering if there is a better way to handle it. However, I would appreciate any feedback you are willing to provide beyond the specific.

class ObjectPicker:
"""
An object that stores other objects with weights, and is able to
pick out one stored object, with a higher chance for higher weighted
objects.
"""

def __init__(self):
    """
    Initialize the Object Picker object. Create the instance variable
    bucket for storing objects.
    """
    self.bucket = []

def add(self, item, weight=1):
    """
    Add an item to the bucket, with given weight.
    :param item: Object to be stored.
    :param weight: Weight given to the object to determine odds.
    """
    if self.bucket:  # If there is anything in the bucket.
        total = self.bucket[-1][-1]  # Get the end number of the last item.
    else:  # If the bucket is empty.
        total = 0  # End number is 0.

    # Object stored in Tuple.
    # (Object, Weight, Starting Num, Ending Num)
    self.bucket.append((item, weight, total, total + weight))

def pick(self, choice=-1, storage=None):
    """
    Pick an object from the bucket recursively,
    taking weight into account.
    :param choice: Number of choice.
    :param storage: Storage Object to choose from.
    """
    if not storage:  # If no storage is given.
        if not self.bucket:  # If bucket is empty.
            return None  # Return None.
        else:
            storage = self.bucket  # Storage is bucket
            total = storage[-1][-1]  # Get final weight.

    if choice < 0:  # If choice is < 0,
        # Randomly choose a number to represent the choice.
        choice = random.random() * total

    # Start binary search in middle of storage object.
    index = len(storage) // 2
    start, end = storage[index][2:]

    # If the choice is lower, recursively search left half.
    if choice < start:
        return self.pick(choice, storage[:index])
    # If the choice is higher, recursively search right half.
    elif choice > end:
        return self.pick(choice, storage[index + 1:])
    # Otherwise, choice is in number spread and return object.
    else:
        return storage[index][0]

I've designed a class ObjectPicker that can be given objects and weights. Objects can be picked randomly out of the ObjectPicker, with heavier weighted objects having a higher chance of being selected.

The pick() method is designed to be recursive and provide \$O(\log n)\$ speed. What I'm not sure about is the defaulting that's currently in place. I'm wondering if there is a better way to handle it. However, I would appreciate any feedback you are willing to provide beyond the specific.

class ObjectPicker:
    """
    An object that stores other objects with weights, and is able to
    pick out one stored object, with a higher chance for higher weighted
    objects.
    """

    def __init__(self):
        """
        Initialize the Object Picker object. Create the instance variable
        bucket for storing objects.
        """
        self.bucket = []

    def add(self, item, weight=1):
        """
        Add an item to the bucket, with given weight.
        :param item: Object to be stored.
        :param weight: Weight given to the object to determine odds.
        """
        if self.bucket:  # If there is anything in the bucket.
            total = self.bucket[-1][-1]  # Get the end number of the last item.
        else:  # If the bucket is empty.
            total = 0  # End number is 0.

        # Object stored in Tuple.
        # (Object, Weight, Starting Num, Ending Num)
        self.bucket.append((item, weight, total, total + weight))

    def pick(self, choice=-1, storage=None):
        """
        Pick an object from the bucket recursively,
        taking weight into account.
        :param choice: Number of choice.
        :param storage: Storage Object to choose from.
        """
        if not storage:  # If no storage is given.
            if not self.bucket:  # If bucket is empty.
                return None  # Return None.
            else:
                storage = self.bucket  # Storage is bucket
                total = storage[-1][-1]  # Get final weight.

        if choice < 0:  # If choice is < 0,
            # Randomly choose a number to represent the choice.
            choice = random.random() * total

        # Start binary search in middle of storage object.
        index = len(storage) // 2
        start, end = storage[index][2:]

        # If the choice is lower, recursively search left half.
        if choice < start:
            return self.pick(choice, storage[:index])
        # If the choice is higher, recursively search right half.
        elif choice > end:
            return self.pick(choice, storage[index + 1:])
        # Otherwise, choice is in number spread and return object.
        else:
            return storage[index][0]
Source Link

Python Weighted Object Picker

I've designed a class ObjectPicker, than can be given Objects and weights. Objects can be picked randomly out of the ObjectPicker, with heavier weighted objects having a higher chance of being selected.

The pick() method is designed to be recursive and provide O(logN) speed. What I'm not sure about is the defaulting that's currently in place. I'm wondering if there is a better way to handle it. However, I would appreciate any feedback you are willing to provide beyond the specific.

class ObjectPicker:
"""
An object that stores other objects with weights, and is able to
pick out one stored object, with a higher chance for higher weighted
objects.
"""

def __init__(self):
    """
    Initialize the Object Picker object. Create the instance variable
    bucket for storing objects.
    """
    self.bucket = []

def add(self, item, weight=1):
    """
    Add an item to the bucket, with given weight.
    :param item: Object to be stored.
    :param weight: Weight given to the object to determine odds.
    """
    if self.bucket:  # If there is anything in the bucket.
        total = self.bucket[-1][-1]  # Get the end number of the last item.
    else:  # If the bucket is empty.
        total = 0  # End number is 0.

    # Object stored in Tuple.
    # (Object, Weight, Starting Num, Ending Num)
    self.bucket.append((item, weight, total, total + weight))

def pick(self, choice=-1, storage=None):
    """
    Pick an object from the bucket recursively,
    taking weight into account.
    :param choice: Number of choice.
    :param storage: Storage Object to choose from.
    """
    if not storage:  # If no storage is given.
        if not self.bucket:  # If bucket is empty.
            return None  # Return None.
        else:
            storage = self.bucket  # Storage is bucket
            total = storage[-1][-1]  # Get final weight.

    if choice < 0:  # If choice is < 0,
        # Randomly choose a number to represent the choice.
        choice = random.random() * total

    # Start binary search in middle of storage object.
    index = len(storage) // 2
    start, end = storage[index][2:]

    # If the choice is lower, recursively search left half.
    if choice < start:
        return self.pick(choice, storage[:index])
    # If the choice is higher, recursively search right half.
    elif choice > end:
        return self.pick(choice, storage[index + 1:])
    # Otherwise, choice is in number spread and return object.
    else:
        return storage[index][0]