Random Python dictionary key, weighted by values

后端 未结 9 2097
遥遥无期
遥遥无期 2020-12-01 03:29

I have a dictionary where each key has a list of variable length, eg:

d = {
 \'a\': [1, 3, 2],
 \'b\': [6],
 \'c\': [0, 0]
}

Is there a cle

相关标签:
9条回答
  • 2020-12-01 04:15

    I modified some of the other answers to come up with this. It's a bit more configurable. It takes 2 arguments, a list and a lambda function to tell it how to generate a key.

    def select_weighted(lst, weight):
       """ Usage: select_weighted([0,1,10], weight=lambda x: x) """
       thesum = sum([weight(x) for x in lst])
       if thesum == 0:
          return random.choice(lst)
       offset = random.randint(0, thesum - 1)
    
       for k in lst:
          v = weight(k)
          if offset < v:
             return k
          offset -= v
    

    Thanks to sth for the base code for this.

    0 讨论(0)
  • 2020-12-01 04:20

    Make a list in which each key is repeated a number of times equal to the length of its value. In your example: ['a', 'a', 'a', 'b', 'c', 'c']. Then use random.choice().

    Edit: or, less elegantly but more efficiently, try this: take the sum of the lengths of all values in the dictionary, S (you can cache and invalidate this value, or keep it up to date as you edit the dictionary, depending on the exact usage pattern you anticipate). Generate a random number from 0 to S, and do a linear search through the dictionary keys to find the range into which your random number falls.

    I think that's the best you can do without changing or adding to your data representation.

    0 讨论(0)
  • 2020-12-01 04:27

    I'd say this:

    random.choice("".join([k * len(d[k]) for k in d]))
    

    This makes it clear that each k in d gets as many chances as the length of its value. Of course, it is relying on dictionary keys of length 1 that are characters....


    Much later:

    table = "".join([key * len(value) for key, value in d.iteritems()])
    random.choice(table)
    
    0 讨论(0)
提交回复
热议问题