Python combination of 2 lists (1 repeat, 1 non-repeat)

What is the best way to find all combinations from 2 lists, where values โ€‹โ€‹in 1 list can be repeated and in another list they cannot be repeated? Right now, I can get all combinations of a repeating list, as in:

import itertools rep = ['A','B','C', 'D'] norep = ['1','2','3','4'] for i in itertools.combinations_with_replacement(rep,4): print i 

I can get all combinations of a non-repeating list:

 for i in itertool.combinations(norep,4): print i 

and I can get combinations of the two lists, as if they were both not repeated:

 for i in itertools.product([0, 1], repeat=4): print [(norep[j] if i else rep[j]) for j, i in enumerate(i)] 

However, I cannot figure out how to get combinations of a repeating and non-repeating list. I would also like to add combinations, including null values, for example ['A', '1', Null].

+4
source share
2 answers

This is what I got. Pretty close to yours:

 from itertools import chain from itertools import combinations # Huge name! from itertools import combinations_with_replacement as cwr from itertools import starmap from itertools import product from operator import add def _weird_combinations(rep, no_rep, n_from_rep, n_from_norep): return starmap(add, product(cwr(rep, n_from_rep), combinations(no_rep, n_from_norep))) def weird_combinations(rep, no_rep, n): rep, no_rep = list(rep), list(no_rep) # Allow Nones in the output to represent drawing less than n elements. # If either input has None in it, this will be confusing. rep.append(None) # We can't draw more elements from no_rep than it has. # However, we can draw as many from rep as we want. least_from_rep = max(0, n-len(no_rep)) return chain.from_iterable( _weird_combinations(rep, no_rep, n_from_rep, n-n_from_rep) for n_from_rep in xrange(least_from_rep, n+1)) 
+2
source

I think I came up with a solution, but please correct me if it is not. I would also like to see if there are more elegant solutions.

First, I came up with the total number of combinations. All combinations without replacement are n! / R! (Nr)! and with replacement equal (m + s-1)! / s! (m-1)! where m and n are the number of elements to choose from, and r and s are the number of elements that you actually select. Since I know the common elements that I want in each combination (let's call it a cap), I find the number of combinations for 0 without changing the type (n = 0) and for the "cap" type of replacement (m = 3) and multiply these numbers together . Then add to this the number of combinations for 1 of the non-replacement type (n = 1) multiplied by the cap-1 combination of the replacement type (m = 2). Do this until you finally add combinations for the โ€œcapโ€ type of replacement (n = 3) multiplied by 0 type of replacement (m = 0) (thanks @ Andrรฉ Nicolas). Code for the number of combinations below.

 import itertools from math import factorial as fact norep = ['A','B','C'] rep = ['1','2','3'] cap = 3 #length of combinations, eg cap=3, combo1=123,combo2=A12,etc combos = 0 for i in range(cap+1): combnorep = fact(len(norep))/(fact(cap-i)*fact(len(norep)-(cap-i))) combrep = fact(len(rep)+i-1)/(fact(i)*fact(len(rep)-1)) combos = combos + combnorep*combrep print combos 

In this example, the number of combos is 38. Then I wanted to print all the combinations. For this, I defined combinations for all substitutions, all without replacement, and any combination of the two, for example. n = 0, m = 3, n = 1, m = 2; etc .. Here is what I came up with:

 for i in range(cap+1): norepcomb = [j for j in itertools.combinations(norep,i)] repcomb = [k for k in itertools.combinations_with_replacement(rep,cap-i)] for l in itertools.product(norepcomb,repcomb): print list(itertools.chain.from_iterable(l)) 

To include none , I would simply include none in my list for replacement combinations. I would like to receive a response to this, especially if there is a better solution or if it does not work, as I think. Thanks!

0
source

Source: https://habr.com/ru/post/1492199/


All Articles