Creating resources combination - python

We have some departures which can be assigned to different arrivals, just like this:
Dep1.arrivals = [A1, A2]
Dep2.arrivals = [A2, A3, A4]
Dep3.arrivals = [A3, A5]
The output of this function should be a list containing every possible combination of arrivals:
Output: [[A1, A2, A3], [A1, A2, A5], [A1, A3, A5], [A1, A4, A5], ...]
Notice that [A1, A3, A3] isn't contained in the list because you can not use an arrival twice. Also notice that [A1, A2, A3] is the same element as [A3, A1, A2] or [A3, A2, A1].
EDIT:
Many solutions given works in this case but not as a general solution, for instance if the 3 sets or arrivals are equal:
Dep1.arrivals = [A1, A2, A3]
Dep2.arrivals = [A1, A2, A3]
Dep3.arrivals = [A1, A2, A3]
Then it returns:
('A1', 'A2', 'A3')
('A1', 'A3', 'A2')
('A2', 'A1', 'A3')
('A2', 'A3', 'A1')
('A3', 'A1', 'A2')
('A3', 'A2', 'A1')
Which is wrong since ('A1', 'A2', 'A3') and ('A3', 'A2', 'A1') are the same solution.
Thank you anyway!

You can do this using a list comprehension with itertools.product:
>>> import itertools
>>> lol = [["A1", "A2"], ["A2", "A3", "A4"], ["A3", "A5"]]
>>> print [x for x in itertools.product(*lol) if len(set(x)) == len(lol)]
Result
[('A1', 'A2', 'A3'),
('A1', 'A2', 'A5'),
('A1', 'A3', 'A5'),
('A1', 'A4', 'A3'),
('A1', 'A4', 'A5'),
('A2', 'A3', 'A5'),
('A2', 'A4', 'A3'),
('A2', 'A4', 'A5')]
Note that this is notionally equivalent to the code that #Kevin has given.
Edit: As OP mentions in his edits, this solution doesn't work with when order of combination is different.
To resolve that, the last statement can be altered to the following, where we first obtain a list of sorted tuple of arrivals, and then convert convert the list to a set, as below:
>>> lol = [["A1", "A2", "A3"], ["A1", "A2", "A3"], ["A1", "A2", "A3"]]
>>> set([tuple(sorted(x)) for x in itertools.product(*lol) if len(set(x)) == len(lol)])
{('A1', 'A2', 'A3')}
>>> lol = [["A1", "A2"], ["A2", "A3", "A4"], ["A3", "A5"]]
>>> set([tuple(sorted(x)) for x in itertools.product(*lol) if len(set(x)) == len(lol)])
{('A1', 'A2', 'A3'),
('A1', 'A2', 'A5'),
('A1', 'A3', 'A4'),
('A1', 'A3', 'A5'),
('A1', 'A4', 'A5'),
('A2', 'A3', 'A4'),
('A2', 'A3', 'A5'),
('A2', 'A4', 'A5')}

You could use product to generate all possible combinations of the departures, and then filter out combinations containing duplicates after the fact:
import itertools
arrivals = [
["A1", "A2"],
["A2", "A3", "A4"],
["A3", "A5"]
]
for items in itertools.product(*arrivals):
if len(set(items)) < len(arrivals): continue
print items
Result:
('A1', 'A2', 'A3')
('A1', 'A2', 'A5')
('A1', 'A3', 'A5')
('A1', 'A4', 'A3')
('A1', 'A4', 'A5')
('A2', 'A3', 'A5')
('A2', 'A4', 'A3')
('A2', 'A4', 'A5')

The question is tagged with itertools but i suspect you did not look at itertools.combinations
arrivals = ['A1', 'A2', 'A3', 'A4']
[a for a in itertools.combinations(arrivals, 3)]
#[('A1', 'A2', 'A3'),
#('A1', 'A2', 'A4'),
# ('A1', 'A3', 'A4'),
#('A2', 'A3', 'A4')]

Related

Python find elements in array A but not in array B

I'm trying to find the difference between the 2 arrays
arrayA = np.array(['A1', 'A2', 'A3'])
arrayB = np.array(['A1', 'A2', 'A3', 'A4', 'A5', 'A6'])
I'm trying to get
difference = ['A4', 'A5', 'A6']
How can I do this, thank you
Use numpy's setdiff:
np.setdiff1d(arrayA, arrayB)
Also - is there any special reason for which this needs to be a numpy array? You could simply use sets and then the minus operator: set(arrayA) - set(arrayB)
[i for i in arrayB if i not in arrayA]
You can use the python set features for this:
import numpy as np
a = np.array(['A1', 'A2', 'A3'])
b = np.array(['A1', 'A2', 'A3', 'A4', 'A5', 'A6'])
print(set(b)-set(a))
Output:
{'A6', 'A5', 'A4'}
Or just comprehension:
import numpy as np
a = np.array(['A1', 'A2', 'A3'])
b = np.array(['A1', 'A2', 'A3', 'A4', 'A5', 'A6'])
print([i for i in b if i not in a])
Output:
['A4', 'A5', 'A6']
As pointed out by this great answer, you can use the np.setdiff1d() method:
import numpy as np
arrayA = np.array(['A1', 'A2', 'A3'])
arrayB = np.array(['A1', 'A2', 'A3', 'A4', 'A5', 'A6'])
print(np.setdiff1d(arrayB, arrayA))
Output
['A4' 'A5' 'A6']
But the order of the elements will not be kept, as the result will always be sorted in ascending order. Observe:
import numpy as np
arrayA = np.array(['A1', 'A2', 'A3'])
arrayB = np.array(['A1', 'A2', 'A3', 'A4', 'A6', 'A5']) # Swapped 5 and 6
print(np.setdiff1d(arrayB, arrayA))
Output:
['A4' 'A5' 'A6']
If you want to keep the order, you can use the np.in1d() method:
import numpy as np
arrayA = np.array(['A1', 'A2', 'A3'])
arrayB = np.array(['A1', 'A2', 'A3', 'A4', 'A6', 'A5']) # Swapped 5 and 6
print(arrayB[~np.in1d(arrayB, arrayA)])
Output:
['A4' 'A6' 'A5']
You can use sets:
difference = list(set(arrayB) - set(arrayA))
Output:
['A4', 'A6', 'A5']

How to get a given number of unique combinations of layers variations, while maintaining a given proportion of each layer variant using Python?

I need to write a script in Python to solve this task, but I can't figure out how to do it.
I have items (let's name them layers): A, B, C...
Each layer can have any number of variations.
For each variation, the proportion percent is given that we want to get at the output.
At the output, we have to get a given number of unique combinations of all layers according to the given proportions.
For example:
layers = [
{'A0':'30%', 'A1':'30%', 'A2':'40%'},
{'B0':'10%', 'B1': '20%', 'B2' '40%', 'B3':'30%'},
{'C0':'50%'}
]
If I want to get exact 10 unique combinations of the A, B, C layers variations,
the script should output the dataset like this:
[
('A0', 'B0'),
('A0', 'B1', 'C0'),
('A0', 'B1'),
('A1', 'B2', 'C0'),
('A1', 'B2'),
('A1', 'B3', 'C0'),
('A2', 'B2', 'C0'),
('A2', 'B2'),
('A2', 'B3', 'C0'),
('A2', 'B3')
]
So, the counts of each layer variation should align with the given proportions:
A0 = 3, A1 = 3, A2 = 4
B0 = 1, B1 = 2, B2 = 4, B3 = 3,
C0 = 5
If we want to get 20 variations the counts will be different:
A0 = 6, A1 = 6, A2 = 8
B0 = 2, B1 = 4, B2 = 8, B3 = 6,
C0 = 10
It should work for any number of layers, variations, proportions and get the exact count of the output combinations
(or the maximum of combinations, if there are no more combinations to get the exact number)
For every layer, you can find the distribution list and then recursively merge the results to produce the combinations. Due to the very high number of combinations that could result from get_combos, the latter is a generator, and you can use next to produce the values on-demand:
import itertools
layers = [{'A0': '30%', 'A1': '30%', 'A2': '40%'}, {'B0': '10%', 'B1': '20%', 'B2': '40%', 'B3': '30%'}, {'C0': '50%'}]
def layer_combos(l, d):
return [i for a, b in l.items() for i in ([a]*int((d*(int(b[:-1])/float(100)))))]
def get_offsets(l, d, c = []):
if not d:
yield tuple(c)
else:
if l:
yield from get_offsets(l[1:], d-1, c+[l[0]])
if not c or c[-1] is not None:
for i in range(d - len(l)):
yield from get_offsets(l, d-(i+1), c+([None]*(i+1)))
def get_combos(l, d, c = []):
if not l:
if len((l:=[tuple(list(filter(None, i))) for i in zip(*c)])) == len(set(l)):
yield l
else:
for i in itertools.permutations((l1:=layer_combos(l[0], d)), (l2:=len(l1))):
for j in set(get_offsets(i, d)):
yield from get_combos(l[1:], d, c + [j])
result = get_combos(layers, 10)
for _ in range(10): #first ten combinations
print(next(result))
Output:
[('A0', 'B0', 'C0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3'), ('A2', 'B2'), ('A2', 'B2', 'C0'), ('A2', 'B3', 'C0'), ('A2', 'B3')]
[('A0', 'B0', 'C0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3'), ('A2', 'B2'), ('A2', 'B2', 'C0'), ('A2', 'B3'), ('A2', 'B3', 'C0')]
[('A0', 'B0', 'C0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2'), ('A1', 'B2', 'C0'), ('A1', 'B3'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3', 'C0'), ('A2', 'B3')]
[('A0', 'B0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2'), ('A1', 'B2', 'C0'), ('A1', 'B3', 'C0'), ('A2', 'B2'), ('A2', 'B2', 'C0'), ('A2', 'B3'), ('A2', 'B3', 'C0')]
[('A0', 'B0'), ('A0', 'B1'), ('A0', 'B1', 'C0'), ('A1', 'B2'), ('A1', 'B2', 'C0'), ('A1', 'B3', 'C0'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3'), ('A2', 'B3', 'C0')]
[('A0', 'B0', 'C0'), ('A0', 'B1'), ('A0', 'B1', 'C0'), ('A1', 'B2'), ('A1', 'B2', 'C0'), ('A1', 'B3'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3', 'C0'), ('A2', 'B3')]
[('A0', 'B0', 'C0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3', 'C0'), ('A2', 'B3')]
[('A0', 'B0', 'C0'), ('A0', 'B1'), ('A0', 'B1', 'C0'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3'), ('A2', 'B3', 'C0')]
[('A0', 'B0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3', 'C0'), ('A2', 'B2', 'C0'), ('A2', 'B2'), ('A2', 'B3', 'C0'), ('A2', 'B3')]
[('A0', 'B0'), ('A0', 'B1', 'C0'), ('A0', 'B1'), ('A1', 'B2', 'C0'), ('A1', 'B2'), ('A1', 'B3', 'C0'), ('A2', 'B2'), ('A2', 'B2', 'C0'), ('A2', 'B3', 'C0'), ('A2', 'B3')]

How to find different combinations between two list?

There are two lists.
list_1=[a1,b1,c1,d1]
list_2=[a2,b2,c2,d2]
Conditions are (i) there must be four elements in each of the combinations and (ii) combinations should contain one element of a (i.e. either a1 or a2),one element of b (i.e. either b1 or b2),one element of c (i.e. either c1 or c2) and one element of d (i.e. either d1 or d2).
Please help me to find out different combinations by using python 3x.
You can use itertools.product:
from itertools import product
list_1 = ['a1','b1','c1','d1']
list_2 = ['a2','b2','c2','d2']
result = list(product(*zip(list_1, list_2)))
print(result)
[('a1', 'b1', 'c1', 'd1'), ('a1', 'b1', 'c1', 'd2'), ('a1', 'b1', 'c2', 'd1'), ('a1', 'b1', 'c2', 'd2'), ('a1', 'b2', 'c1', 'd1'), ('a1', 'b2', 'c1', 'd2'), ('a1', 'b2', 'c2', 'd1'), ('a1', 'b2', 'c2', 'd2'), ('a2', 'b1', 'c1', 'd1'), ('a2', 'b1', 'c1', 'd2'), ('a2', 'b1', 'c2', 'd1'), ('a2', 'b1', 'c2', 'd2'), ('a2', 'b2', 'c1', 'd1'), ('a2', 'b2', 'c1', 'd2'), ('a2', 'b2', 'c2', 'd1'), ('a2', 'b2', 'c2', 'd2')]

Duplicating and Inserting into Nested List Python

I currently have nested list:
A = [[a1, a2, a3], c1, [a4, a5, a6], c2]
I also have another list:
B = [b1, b2]
I wish to duplicate A by the number of elements in B and then insert list B in the following way:
AB = [[a1, a2, a3], b1, c1, [a4, a5, a6], b1, c2, [a1, a2, a3], b2, c1, [a4, a5, a6], b2, c2]
The duplication I have managed to figure out easily:
AB = A * len(B)
However, the inserting of a list into a nested list has me completely stumped.
I'm currently using Python 3.6.1 and the size of list A and B can change but are always in the format of:
A template = [[x1, x2, x3], z1 ...]
B template = [y1, ...]
Any assistance will be greatly appreciated.
You can do it in a simple manner.
A = [['a1', 'a2', 'a3'], 'c1', ['a4', 'a5', 'a6'], 'c2']
AB=[]
B = ['b1', 'b2']
for i in B:
for j in A:
if isinstance(j,list):
AB.append(j)
else:
AB.append(i)
AB.append(j)
print AB
Output:[['a1', 'a2', 'a3'], 'b1', 'c1', ['a4', 'a5', 'a6'], 'b1', 'c2', ['a1', 'a2', 'a3'], 'b2', 'c1', ['a4', 'a5', 'a6'], 'b2', 'c2']

Swapping two dimensional array using python

I need help in swapping 2 elements using Python for the following type of list that is generated randomly:
Actual list
list = [('a0', 'b5'), ('a0', 'b6'), ('a1', 'b0'), ('a1', 'b2'), ('a1', 'b3'), ('a1', 'b5'), ('a1', 'b6'), ('a2', 'b0'), ('a2', 'b2'), ('a2', 'b5'), ('a3', 'b4')]
After swapping element 'a1' with 'a2'
Array [('a0', 'b5'), ('a0', 'b6'), ('a2', 'b0'), ('a2', 'b2'), ('a2', 'b5'), ('a3', 'b4'), ('a1', 'b0'), ('a1', 'b2'), ('a1', 'b3'), ('a1', 'b5'), ('a1', 'b6')]
This is my code:
r1 = random.randrange(1, 5, 1)
r2 = random.randrange(4, 9, 2)
a = ['a' + str(j) for j in range(r1)]
b = ['b' + str(j) for j in range(r2)]
dd = []
total = math.floor((r1 * r2) * 80 / 100)
print("80% connection", total)
for x in a:
for y in b:
r3 = random.randrange(1, total, 2)
if (r3 < 10):
dd.append((x, y))
print("Connection", dd)
cop = [eb[0] for eb in dd]
s1 = random.randrange(len(a))
s2 = random.randrange(len(a))
print("Number to Swap", s1)
print("Range Number Two", s2)
for swp in range(len(dd)):
if swp ==s1:
for tes in range(len(a)):
if a[s1] == cop[swp]:
temp = dd[s1]
dd[s1] = dd[s2]
dd[s2] = temp
else:
for tes in range(len(a)):
if a[s2] == cop[swp]:
temp = dd[s1+1]
dd[s1+1] = dd[swp]
dd[swp] = temp
print("New Swap Array", dd)
This works with lists similar to your example, swaps elements only when the actual list contains tuples with 'a1' or 'a2' as the first element, could easily be modified to work with other and more elements.
new_dd = []
first_els = []
second_els = []
end_els = []
for i in dd:
if int(i[0][1]) < 1:
new_dd.append(i)
elif int(i[0][1]) > 2:
end_els.append(i)
elif int(i[0][1]) == 1:
first_els.append(i)
elif int(i[0][1]) == 2:
second_els.append(i)
new_dd.extend(second_els)
new_dd.extend(first_els)
new_dd.extend(end_els)
print(dd)
print(new_dd)
Output:
[('a0', 'b1'), ('a0', 'b2'), ('a0', 'b3'), ('a1', 'b0'), ('a1', 'b1'), ('a1', 'b2'), ('a1', 'b3'), ('a2', 'b0'), ('a2', 'b1'), ('a2', 'b2'), ('a2', 'b3'), ('a3', 'b0'), ('a3', 'b2'), ('a3', 'b3')]
[('a0', 'b1'), ('a0', 'b2'), ('a0', 'b3'), ('a2', 'b0'), ('a2', 'b1'), ('a2', 'b2'), ('a2', 'b3'), ('a1', 'b0'), ('a1', 'b1'), ('a1', 'b2'), ('a1', 'b3'), ('a3', 'b0'), ('a3', 'b2'), ('a3', 'b3')]

Categories

Resources