Search code examples
pythonlistrandomrankingweighted

Return list of weighted objects with semi-randomized ranking


Let's say I have a list of objects (in Python) that looks something like this (contains an identifier and a ranking/weighting):

objects = [
    ("object_1", 0.50),
    ("object_2", 0.75),
    ("object_3", 0.25),
    ("object_4", 0.01),
    ("object_5", 0.99),
]

I would like to return this same objects array but in semi-randomised order of their weighting. That is, I don't always want to return:

[
    ("object_5", 0.99),
    ("object_2", 0.75),
    ("object_1", 0.50),
    ("object_3", 0.25),
    ("object_4", 0.01),
]

but would instead rather allow for some non-determinism so that, generally speaking, the returned array looks like the above but could also look like:

[
    ("object_5", 0.99),
    ("object_1", 0.50),
    ("object_2", 0.75),
    ("object_4", 0.01),
    ("object_3", 0.25),
]

EDIT: I think I'm asking a different question than this one because the ordering matters here; and in the other question the order doesn't matter (again, I think!).


Solution

  • If you are able to ensure that the weight values are always in between [0, 1), then the following code will work!

    from random import random
    
    
    def weighted_sample_without_replacement(
        population: List[Tuple[Any, float]], weights: tuple
    ) -> List[Tuple[Any, float]]:
        return sorted(population, key=lambda x: x[1] * random())
    

    where population looks like:

    [
        ("object_5", 0.99),
        ("object_2", 0.75),
        ("object_1", 0.50),
        ("object_3", 0.25),
        ("object_4", 0.01),
    ]
    

    weights like:

    (
        0.99,
        0.75,
        0.50,
        0.25,
        0.01,
    )