Related
For a MILP project planning problem I would like to formulate the constraint that activity i must be finished before activity j starts. The activities are to be ordered by duration p and the one of three modes m per activity is to be used which takes the shortest time.
So I created a dictionary with the minimum durations of activity i in mode m.
p_im_min = {i: np.min([p[i,m] for m in M_i[i]]) for i in V}
Then I sorted the durations by size:
p_sort = (sorted(p_im_min.items(), key = lambda kv: kv[1]))
Which gives (i,p) in the right order:
p_sort = [(0, 0),
(3, 1),
(4, 1),
(5, 1),
(7, 1),
(13, 1),
(14, 1),
(15, 1),
(19, 1),
(1, 2),
(2, 2),
(8, 2),
(16, 2),
(17, 2),
(18, 2),
(20, 2),
(6, 3),
(10, 3),
(9, 4),
(12, 4),
(11, 5)]
But now I want a list with (i,j), where i must always be finished before j starts. Since I could not find the function, I created this list manually, thus
order_act = [(0,3),
(3,4),
(4,5),
(5,7), etc.
And finally (after formulating the parameters, variables and sets) added the following constraint:
mdl.addConstrs(y[i,j] == 1
for (i,j) in order_act)
My question:
Is there any way to use a formula/command in Python to create the list (i,j)? Because as it is now, it is not ideal and the solution is not satisfactory.
In Python is there a way to get all 3 pairs or n pairs of a list from a list?
For example list = [1,2,3,4]
result : [[1,2,3],[2,3,4],[1,2,4]]
I want to find all possible n pairs of lists from a Python list. I do not want to import any other functions like itertools.
You can use the module itertools. It comes inside Python by default (you don't need to install it throught third party modules):
>>> import itertools
>>> print(itertools.permutations([1,2,3,4], 3))
[(1, 2, 3), (1, 2, 4), (1, 3, 2), (1, 3, 4), (1, 4, 2), (1, 4, 3), (2, 1, 3), (2, 1, 4), (2, 3, 1), (2, 3, 4), (2, 4, 1), (2, 4, 3), (3, 1, 2), (3, 1, 4), (3, 2, 1), (3, 2, 4), (3, 4, 1), (3, 4, 2), (4, 1, 2), (4, 1, 3), (4, 2, 1), (4, 2, 3), (4, 3, 1), (4, 3, 2)]
This itertools.permutations(iterable, r=None) produces all the possible permutations of a given iterable element (like a list). If r is not specified or is None, then r defaults to the length of the iterable and all possible full-length permutations are generated.
If you are looking only for n pair of permutations instead of all the possible permutations just delete the rest of them:
>>> print(list(itertools.permutations([1,2,3,4], 3))[:3])
[(1, 2, 3), (1, 2, 4), (1, 3, 2)]
As you asked in comments you can do that without importing any module. itertools.permutations is just a function, which you can make by yourself:
def permutations(iterable, r=None):
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
if r > n:
return
indices = list(range(n))
cycles = list(range(n, n-r, -1))
yield tuple(pool[i] for i in indices[:r])
while n:
for i in reversed(range(r)):
cycles[i] -= 1
if cycles[i] == 0:
indices[i:] = indices[i+1:] + indices[i:i+1]
cycles[i] = n - i
else:
j = cycles[i]
indices[i], indices[-j] = indices[-j], indices[i]
yield tuple(pool[i] for i in indices[:r])
break
else:
return
But I strongly advise your importing it. If you don't want to import the whole module, just this function simply do from itertools import permutations.
This is the code that i have written which basically describes the flight connectivity having one city in common between the source and the destination. It seems right for most of the test cases but isn't satisfying this particular one.
def onehop(lis):
hop=[]
for (i,j) in lis:
for (k,l) in lis:
if i==k and j!=l:
return sorted(lis)
if (i!=k and j!=l)and(i==l or j==k) and (((i,j) not in hop) and ((k,l) not in hop)):
m=lis.pop(lis.index((i,j)))
n=lis.pop(lis.index((k,l)))
hop.extend([m,n])
for i in range(len(hop)):
if hop[i][0]>hop[i][1]:
hop[i]=(hop[i][1],hop[i][0])
ans=sorted(hop,key=lambda item: (item[0],item[1]))
return ans
onehop([(2,3),(1,2),(3,1),(1,3),(3,2),(2,4),(4,1)])
Output I expected:
[(1, 2), (1, 3), (1, 4), (2, 1), (3, 2), (3, 4), (4, 2), (4, 3)]
Output I obtained:
[(1, 2), (1, 3), (2, 3), (2, 4), (3, 1), (3, 2), (4, 1)]
def onehop(lis):
hop=[]
for (i,j) in lis:
for (k,l) in lis:
if j==k and i!=l :
hop.append([i,l])
unique = [list(x) for x in set(tuple(x) for x in hop)]
ans=sorted(unique,key=lambda item: (item[0],item[1]))
ans1 = [tuple(l) for l in ans]
return(ans1)
Suppose that I have list:
list = [(4, 7), (3, 7), (5, 7), (4, 6), (4, 8), (2, 7), (3, 6), (3, 8), (6, 7)]
That I want to divide the list into sublists of lengths: [2, 3, 4] (these lengths can vary)
To produce: sublist_list = [[(4, 7), (3, 7)],[(5, 7), (4, 6), (4, 8)], [(2, 7), (3, 6), (3, 8), (6, 7)]]
What's the quickest way that I can do this? Thanks in advance.
myList = [(4, 7), (3, 7), (5, 7), (4, 6), (4, 8), (2, 7), (3, 6), (3, 8), (6, 7)]
listOfLengths = [2, 3, 4]
def getSublists(listOfLengths,myList):
listOfSublists = []
for i in range(0,len(listOfLengths)):
if i == 0:
listOfSublists.append(myList[:listOfLengths[i]])
else:
listOfSublists.append(myList[listOfLengths[i-1]:listOfLengths[i-1]+listOfLengths[i]])
return listOfSublists
Then if you call getSublists on your myList (original list input) and listOfLengths (a list containing the length of your sublists), you get
#In: getSublists(listOfLengths,myList)
#Out: [[(4, 7), (3, 7)], [(5, 7), (4, 6), (4, 8)], [(4, 6), (4, 8), (2, 7), (3, 6)]]
You can user list[i:j] feature in python which returns a new list contains
list[i] to list[j-1] elements of original list.
base = 0
Lengths =[] #list of lengths
for num in Length:
sub_list.append(List[base:num+base])
base += num #jump to next length
What about simply iterating the list and appending to the new lists?
c = 0
for sublist in list:
sublistlist[len(sublistlist)-1].append(sublist)
c += 1
if c % 2:
sublistlist.append([])
I am trying to write a function that will help me break down a fraction into simple components like so
I wrote this function
from fractions import Fraction
def lowest_fraction(frac):
num = frac[0]
den = frac[-1]
if frac == (1, den):
yield frac
while frac != (1, den):
new_num = num - num//2
rem = num - new_num
new_frac = Fraction(new_num, den)
frac = (new_frac.numerator, new_frac.denominator)
num = rem
yield frac
I ran the below
for each in [(1, 2), (3, 4), (3, 8), (5, 8), (7, 8), (7, 16), (9, 32)]:
print('{}: '.format(each))
for k in lowest_fraction(each):
print('\t{}'.format(k))
Here's the output
(1, 2):
(1, 2)
(3, 4):
(1, 2)
(1, 4)
(3, 8):
(1, 4)
(1, 8)
(5, 8):
(3, 8)
(1, 8)
(7, 8):
(1, 2)
(1, 4)
(1, 8)
(7, 16):
(1, 4)
(1, 8)
(1, 16)
(9, 32):
(5, 32)
(1, 16)
(1, 32)
You can see that the output for (3, 8) and (9, 32) is not in their simplest form. I think what I want to do can be accomplished by writing a recursive code but I cannot presently write one because I don't fully grab the concept of recursion yet.