简体   繁体   中英

All posible combinations of numbers on a list

I need to find all the possible combinations of a list with a defined length and numbers of defined size, but subject to a restriction that does not allow having the same repeated number in the list (except 0). Currently I have a recursive code that generates all the combinations, but when trying to create the constraints I lose many options. I have tried the options that appear commented to solve it, but it still does not work for me. Thank you in advance for your help.

size=3
l=[0 for x in range(size)]

def recursive(l, index, num, final):
    if index == len(l) or num == final:
        return
#     if num!=0 and num in l:
#         return
    l[index]=num
    print(l)
    recursive(l, index+1, 0, final)
    recursive(l, index, num+1, final)
recursive(l, 0, 0, 4)

the expected output for a list of size 3 and final number 3 would be something like this

[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 0, 3]
[0, 1, 0]
[0, 1, 2]
[0, 1, 3]
[0, 2, 0]
[0, 2, 1]
[0, 2, 3]
[0, 3, 0]
[0, 3, 1]
[0, 3, 2]
[1, 0, 0]
[1, 0, 2]
[1, 0, 3]
[1, 2, 0]
[1, 2, 3]
[1, 3, 0]
[1, 3, 2]
[2, 0, 0]
[2, 0, 1]
[2, 0, 3]
[2, 1, 0]
[2, 1, 3]
[2, 3, 0]
[2, 3, 1]
[3, 0, 0]
[3, 0, 1]
[3, 0, 2]
[3, 1, 0]
[3, 1, 2]
[3, 2, 0]
[3, 2, 1]

Start with the powerset of the non-zero values (a function for computing the powerset of a list can be found in the itertools documentation.)

def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

>>> list(powerset([1,2,3]))
[(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]

(You could compute the power set including 0, but you would still need to zero-pad the shorter elements, as well as discard (0,1,2,3) ).

Each element of the powerset should next be padded with zeros so that they are all the same length.

Finally, you want the list of permutations (using itertools.permutations ) of each 0-padded permutation of the original input.

Use itertools.combinations_with_replacement() , and then filter out the elements with duplicates.

def has_duplicates(l):
    '''Return True if list has duplicate elements other than 0'''
    l = [x in l if x != 0]
    return len(l) != len(set(l))

result = [comb for comb in itertools.combinations_with_replacement(l, 3) if not has_duplicates(comb)]

You can make this lazy by using itertools.filterfalse() ; this way you won't fill up memory with all combinations of a large list.

result = itertools.filterfalse(has_duplicates, itertools.combinations_with_replacement(l, 3))

Here is a solution based on counters, I am using a base 4 counter:

def charcnt(s, a):
    ctr = [1 if x == a else 0 for x in s ]
    return sum(ctr)
    

def my_range(start,end,base,step=1):
    def Convert(n,base):
       string = "0123"
       if n < base:
          return string[n]
       else:
          return Convert(n//base,base) + string[n%base]
    return (Convert(i,base) for i in range(start,end,step))

# base-10 58 will produce base-4 321
counter = [x.zfill(3) for x in my_range(0, 58, 4)]

result = []
for s in counter:
    if charcnt(s, '1') > 1 or charcnt(s, '2') > 1 or charcnt(s, '3') > 1:
        continue
    else:
        result.append(s)

result = [[int(n) for n in list(s)] for s in result]
#print(len(result))
for i in result:
    print(i)

Will produce:

[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 0, 3]
[0, 1, 0]
[0, 1, 2]
[0, 1, 3]
[0, 2, 0]
[0, 2, 1]
[0, 2, 3]
[0, 3, 0]
[0, 3, 1]
[0, 3, 2]
[1, 0, 0]
[1, 0, 2]
[1, 0, 3]
[1, 2, 0]
[1, 2, 3]
[1, 3, 0]
[1, 3, 2]
[2, 0, 0]
[2, 0, 1]
[2, 0, 3]
[2, 1, 0]
[2, 1, 3]
[2, 3, 0]
[2, 3, 1]
[3, 0, 0]
[3, 0, 1]
[3, 0, 2]
[3, 1, 0]
[3, 1, 2]
[3, 2, 0]
[3, 2, 1]

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