简体   繁体   中英

Generate a percent of all possible combinations from a list of numbers

I know that itertools.combinations(iterable, r) returns combinations of a list/tuple of elements (as an iterable). How can I build a function around it that returns only x% of all combinations? (i just need a list of tuples, so it does not have to be an iterator). I want that if there are very few combinations, for example nCn, it should return all (in this case one) of them (so minimum 1).

With itertools.islice you can produce an iterator with an upper bound in the number of elements:

import itertools

MAX_COMBS = 2
combs = itertools.combinations(range(3), 2)
combs_slice = itertools.islice(combs, MAX_COMBS)
print(*combs_slice, sep='\n')
# (0, 1)
# (0, 2)

If the size of the iterable has a len , then you can make the upper limit dependant on the total number of combinations:

import itertools
import math

# Percentage of combinations to draw
COMB_RATIO = 0.2
# Lower bound for number of combinations
MIN_COMBS = 2

iterable = range(5)
k = 3
combs = itertools.combinations(iterable, k)
max_combs = max(round(COMB_RATIO * math.comb(len(iterable), k)), MIN_COMBS)
combs_slice = itertools.islice(combs, max_combs)
print(*combs_slice, sep='\n')
# (0, 1, 2)
# (0, 1, 3)
# (0, 1, 4)

iterable = range(3)
k = 2
combs = itertools.combinations(iterable, k)
max_combs = max(round(COMB_RATIO * math.comb(len(iterable), k)), MIN_COMBS)
combs_slice = itertools.islice(combs, max_combs)
print(*combs_slice, sep='\n')
# (0, 1)
# (0, 2)

Note: math.comb was introduced in Python 3.8, if you are in a previous version you may need to roll your own implementation, or take it eg from SciPy .

Because iterators don't carry the information of how long their collections are, you cannot obtain the length from it.

In your case, you could determine the size of the combination using the formula n!/(k! (nk)!) and iterate until your percentage.

For instance:

from math import factorial, ceil

def my_combinations():
    ratio = .2 # 20 percent
    a = range(10)
    n = len(a)
    k = 5
    it = itertools.combinations(a, k)
    total_combinations = factorial(n) / factorial(k) / factorial(n-k)

    for _ in range(ceil(total_combinations * ratio)):
        yield it.next()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM