I have 4 arrays with 2 columns: one column measuring meters and the other measuring the money you get per meter, I want to get the highest sum combinations from these 4 arrays but I have 2 rules : the first rule is that each meter value in the sum has to be between 1 and 6 meters, and the second rule is that the meter value of the result has to be equal to 12 meters. I have written a code that gets the maximum sum out of a series of 4 arrays but I don't know how to implement the 2 rules in the code. This is why i am asking for your help.
My 4 arrays :
1,2,3,4,5,6 are the meter values
and the numbers below the meter values is the money earned by meters
A = [[1, 2, 3, 4, 5, 6],
[50.4, 100.8, 201.6, 403.2, 806.4, 1612.8]]
B = [[1, 2, 3, 4, 5, 6],
[40.8, 81.6, 163.2, 326.4, 652.8, 1305.6]]
C = [[1, 2, 3, 4, 5, 6],
[110, 220, 440, 880, 1760, 3520]]
D = [[1, 2, 3, 4, 5, 6],
[64, 128, 256, 512, 1024, 2048]]
My code :
import math
from queue import PriorityQueue
def KMaxCombinations(A, B, C, D, N, K):
# Max heap.
pq = PriorityQueue()
# Insert all the possible
# combinations in max heap.
for i in range(0,N):
for j in range(0,N):
for k in range(0,N):
for l in range(0,N):
a = A[i] + B[j] + C[k] + D[l]
pq.put((-a, a))
# Pop first N elements from
# max heap and display them.
count = 0
while (count < K):
print(pq.get()[1])
count = count + 1
# Driver method
A = [50.4, 100.8, 201.6, 403.2, 806.4, 1612.8]
B = [40.8, 81.6, 163.2, 326.4, 652.8, 1305.6]
C = [110, 220, 440, 880, 1760, 3520]
D = [64, 128, 256, 512, 1024, 2048]
N = len(A)
K = 3
# Function call
KMaxCombinations(A, B, C, D, N, K)
As it has been said in the comments other approaches may be more efficient. And of course we need to put the meters data in the list together with the prices:
A = [(1, 50.4), (2, 100.8), (3, 201.6), (4, 403.2), (5, 806.4), (6, 1612.8)]
B = [(1, 40.8), (2, 81.6), (3, 163.2), (4, 326.4), (5, 652.8), (6, 1305.6)]
C = [(1, 110), (2, 220), (3, 440), (4, 880), (5, 1760), (6, 3520)]
D = [(1, 64), (2, 128), (3, 256), (4, 512), (5, 1024), (6, 2048)]
Then, if we want to keep your approach (just allow me to use itertools.product instead of those 4 for loops) a possible solution would be:
def KMaxCombinations(A, B, C, D, N, K):
pq = PriorityQueue()
for p in product(A, B, C, D):
meters, prices = list(zip(*p))
for m in meters:
if not (0<m<7):
allgood = False
break
else:
allgood = True
if allgood and (sum(meters) == 12):
a = sum(prices)
pq.put((-a, a))
count = 0
while (count < K):
print(pq.get()[1])
count = count + 1
KMaxCombinations(A,B,C,D,N,K)
4123.2
4028.0
3960.8
Here's a modification of posted code to solve for solution.
Using exhaustive search as posted code
Changes:
Used heapq as PriorityQueue
Made A, B, C, D 2-dimensional lists to add meters
Added if conditionals to implement rules
Code
import heapq
def KMaxCombinations(A, B, C, D, N, K):
# Trying all combinations of the rows of A, B, C, D
priority_queue = []
for i in range(0,N):
if 1 <= A[0][i] <= 6: # the first rule is that each meter value in the sum has to be between 1 and 6 meters
for j in range(0,N):
if 1 <= B[0][j] <= 6: # the first rule is that each meter value in the sum has to be between 1 and 6 meters
for k in range(0,N):
if 1 <= C[0][k] <= 6: # the first rule is that each meter value in the sum has to be between 1 and 6 meters
for l in range(0,N):
if 1 <= D[0][l] <= 6: # the first rule is that each meter value in the sum has to be between 1 and 6 meters
# second rule is that the meter value of the result has to be equal to 12 meters
if A[0][i] + B[0][j] + C[0][k]+ D[0][l] == 12:
money_obtained = A[1][i] + B[1][j] + C[1][k] + D[1][l]
# Add another solution to priority queue
heapq.heappush(priority_queue, (-money_obtained, i, j, k, l))
return heapq.nsmallest(K, priority_queue)[K-1] # K-th most money
# use smallest since money is negative
# value to make max heap
Test
# Use 2D list for meters and money
# A[0] - list of meters
# A[1] - list of money
# same for B, C, D
A = [[1, 2, 3, 4, 5, 6],
[50.4, 100.8, 201.6, 403.2, 806.4, 1612.8]]
B = [[1, 2, 3, 4, 5, 6],
[40.8, 81.6, 163.2, 326.4, 652.8, 1305.6]]
C = [[1, 2, 3, 4, 5, 6],
[110, 220, 440, 880, 1760, 3520]]
D = [[1, 2, 3, 4, 5, 6],
[64, 128, 256, 512, 1024, 2048]]
K = 3 # 3rd best solution
solution = KMaxCombinations(A, B, C, D, len(A[0]), K)
# Show result
if solution:
max_money,*sol = solution
print(f'{K}rd Max money is {max_money}')
print(f'Using A[{sol[0]}] = {A[0][sol[0]]}')
print(f'Using B[{sol[1]}] = {A[0][sol[1]]}')
print(f'Using C[{sol[2]}] = {A[0][sol[2]]}')
print(f'Using D[{sol[3]}] = {A[0][sol[3]]}')
print(f'Sum A, B, C, d meters is: {A[0][sol[0]] + B[0][sol[1]] + C[0][sol[2]] + D[0][sol[3]]}')
else:
print("No Solution")
Output
3rd Max money is 3960.8
Using A[0] = 1
Using B[3] = 4
Using C[5] = 6
Using D[0] = 1
Sum A, B, C, d meters is: 12
This can be solved with additional info that wasn't in the question. The meter number is just the one-based index of the array. (see comments, and OP: please edit that info into the question. External links to pictures aren't allowed.)
Since you're not familiar with dynamic programming, and this problem suits itself to a brute force approach, we'll do that. You just need the meter number to check the constraints, which you can get from python's enumerate.
https://docs.python.org/3/library/functions.html#enumerate
Your for loops over a container should not be based on an index, but rather something simple like "for a in A", but since we want the index as well, let's do this
for a_meter, a_value in enumerate(A, start=1):
for b_meter, b_value in enumerate(B, start=1):
for c_meter, c_value in enumerate(C, start=1):
for d_meter, d_value in enumerate(D, start=1):
if check_constraints(a_meter, b_meter, c_meter, d_meter):
value = sum((a_value, b_value, c_value, d_value))
pq.put(-value, value)
We can check the constraints first, and only include the values that pass in the priority queue.
def check_constraints(a, b, c, d):
return sum((a, b, c, d)) == 12
When you do this kind of brute forcing, you really want to use itertools. What you've done with these for loops is basically itertools.product.
https://docs.python.org/3/library/itertools.html#itertools.product
Additionally, itertools doesn't care how many different sets of meters you have. It would be easy (with some practice) to write a function like KMaxCombinations(collection_of_meters, target=12, K=3) using itertools.
Additionally, you can chain iterators like enumerate directly into the product. You can also use itertools.islice to skip candidates that can't meet the criteria. That doesn't help in this particular problem, but if the 12 were different, it might be high enough that you can entirely skip the first few readings. Or if it's low enough, you can skip the last several readings.
Related
i used itertools.combinations to list all possible combinations of a list...but how do i pick only the neighbors so that the users are all together
list =[1,2,3,4,5,6,7,8,9,10,11,12]
occupied = [2,6,7,11]
remaining seats are available... Now how do i arrange two folks together always in the available seats..
1 0
3 4
5 0
0 8
9 10
0 12
the right combinations are (1,3) (3,4) (3,5) (8,9) (9,10) (10,12) (since its two folks..we can interchange them.. so two possible ways)... altogether at the moment i have 28...how do i remove the rest..any guidance would be appreciated
/*just added my code/
import numpy as np
import itertools
from itertools import permutations, combinations, combinations_with_replacement
def seatingarrangement (arr):
arry = arr.split(',')
larr = [int(x) for x in arry]
total = (larr[0])
occ = larr[1:]
totals = [x+1 for x in range(0,total)]
print(totals)
for val in totals:
if val in occ:
item= totals.index(val)
totals[item] = 0
print(totals)
#result = list(filter(lambda x: x!=0, totals))
result = [x for x in totals if x != 0]
print(result)
comb = combinations(result,2)
data = itertools.dropwhile(lambda x: x < 5, [3, 12, 7, 1, -5])
print(list(comb))
avl = []
#total there are 8 seats and two users are to be seated next to each other always ... #moreover the seats are not all consecutive
for i,x in enumerate(totals):
if (i+1)%2 == 0:
print('even#:',i+1,'is :',x)
data = itertools.dropwhile()
print(data)
else:
print('odd#:',i+1,'is :',x)
I'd suggest a method that verifies the validity of a pair, regarding the occupied list and the position
def is_pair_valid(pair, occupied_list):
# check occupied
x, y = min(pair), max(pair)
if x in occupied_list or y in occupied_list:
return False
# check neighbours
diff = y - x
return diff in (2, 1, -2) if x % 2 == 1 else diff in (2, -1, -2)
odd number : the other should be at distance +2, +1 or -2 (ex 3 with 1,4,5)
even number : the other should be at distance +2, -1 or -2 (ex 4 with 2,3,6)
Then
values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
occupied = [2, 6, 7, 11]
for p in filter(lambda x: is_pair_valid(x, occupied), combinations(values, r=2)):
print(p)
Gives the correct
(1, 3)
(3, 4)
(3, 5)
(8, 10)
(9, 10)
(10, 12)
Here two cells are considered adjacent if they share a boundary.
For example :
A = 5 6 4
2 1 3
7 9 8
Here adjacent elements to index 0,0 is at index [0,1] and [1,0] and for index 1,1 the adjacent elements are at index [0,1],[1,0],[2,1] and [1,2].
Supposed you have mxn matrix, and you want to find the adjacent indices of the cell (i, j):
def get_adjacent_indices(i, j, m, n):
adjacent_indices = []
if i > 0:
adjacent_indices.append((i-1,j))
if i+1 < m:
adjacent_indices.append((i+1,j))
if j > 0:
adjacent_indices.append((i,j-1))
if j+1 < n:
adjacent_indices.append((i,j+1))
return adjacent_indices
To also check for diagonals, regarding what Casper Dijkstrao asked, I usually write some code like this:
def adj_finder(matrix, position):
adj = []
for dx in range(-1, 2):
for dy in range(-1, 2):
rangeX = range(0, matrix.shape[0]) # X bounds
rangeY = range(0, matrix.shape[1]) # Y bounds
(newX, newY) = (position[0]+dx, position[1]+dy) # adjacent cell
if (newX in rangeX) and (newY in rangeY) and (dx, dy) != (0, 0):
adj.append((newX, newY))
return adj
The function gets the matrix argument to extract the size of its row and column (I use numpy, so matrix.shape returns (row_size, column_size) tuple).
It also gets the current cell as pointer argument (it's like (X,Y)).
Then It generate adjacent cells, and if they were legit (1. they were not out of the bound, and 2. not identical to reference position), it adds them to adjacent list, adj.
I'd like to emphasize that using the above algorithm, you can easily obtain neighbors in farther distances as well. Just modify the range in the for loops, like this:
for v in range(0-distance, 1+distance):
for h in range(0-distance, 1+distance):
...
Where distance is the maximum distance of adjacent you want to let in.
This will be another way - prob. involve some math tricks or regarded more concise (if you're more math-inclined) :
def neighbours(grid, r, c):
vals = sum((row[c -(c>0): c+2]
for row in grid[r -(r>0):r+2]), [])
vals.remove(grid[r][c]) # rm itself.
return vals
grid = [[1, 5, 4, 9],
[2, 8, 3, 8],
[6, 3, 6, 3],
[7, 4, 7, 1]]
Outputs: (all items are in order)
print(f' {neighbours(grid, 2, 2)} ') # [8, 3, 8, 3, 3, 4, 7, 1]
print(f' {neighbours(grid, 0, 0)} ') # [5, 2, 8]
print(f' {neighbours(grid, 1, 1)} ') # [[1, 5, 4, 2, 3, 6, 3, 6]
I am trying to write a code that takes
m. a, a list of integers
n. b, an integer
and returns the number of pairs (m,n) with m,n in a such that |m-n|<=b.
So far, I've got this
def nearest_pairs(a, b):
m= []
n= int
num_pairs = 0
return num_pairs
def main():
# The nearest pairs are (1,2), (2,1), (2,5) and (5,2)
x = nearest_pairs( [1,2,5] , 3 )
print( "nearest_pairs([1, 2, 5], 3) = " , nearest_pairs([1, 2, 5], 3) )
# The nearest pairs are (1,2) and (2,1)
y = nearest_pairs( [1, 2, 5] , 2 )
print( "nearest_pairs([1, 2, 5], 2) = " , nearest_pairs([1, 2, 5], 2) )
if __name__ == '__main__':
main()
The desired output should look like
>>> nearest_pairs([1,2,5],3) = 4
where 4 is the number of close pairs according to the restrictions. However, I get an error. Could anyone lead me to the right direction?
Yours doesn't make sense. No idea what you're trying with len(a, b), but it's not even allowed, since len takes only one argument. And returning something just when you found the first counting pair? Here's a fix:
def close_pairs(l, d):
ctr = 0
for a,b in permutations(l, 2):
if (a - b) <= d and (b - a) <= d:
ctr += 1
return ctr
And here's how I'd do it:
def close_pairs(l, d):
return sum(abs(a-b) <= d for a, b in permutations(l, 2))
from itertools import permutations
def nearest_pairs(a, b):
for m, n in permutations(a, 2):
if abs(m - n) <= b:
yield (m, n)
>>> list(nearest_pairs([1, 2, 5], 3))
[(1, 2), (2, 1), (2, 5), (5, 2)]
>>> list(nearest_pairs([1, 2, 5], 2))
[(1, 2), (2, 1)]
If you just want the count:
def nearest_pairs_count(a, b):
c, l = 0, len(a)
for i in range(l):
for j in range(i + 1, l):
if abs(a[i] - a[j]) <= b:
c += 2
return c
Suppose I have a huge list of tuples:
tuples = ([1, 2], [2, 1], [3, 2], [25, 73], [1, 3]...)
This list has 360000 elements as of now (they are a list of coprimes numbers). I need to make combinations of 3 tuples, such that there are only 3 different numbers on each combination, example:
([2, 1], [3, 1], [3, 2])
([2, 1], [5, 1], [5, 2])
I need to discard combinations with 4 or more different numbers while generating the list of combinations.
If I try to bruteforce this and test each combination, I end up with 360000 choose 3 which is 7.77 * 10^15possible combinations to test.
EDIT:
The problem I am trying to solve is:
Find all combinations of coprime pairs in the form:
(a, b), (a, c), (b, c)
for c < 120000
Steps I've taken:
Generate the ternary tree for all Coprime pairs whereboth numbers are less than 120000
(ISSUE - Generate the combinations, bruteforcing it won't do)
Let's make a dict of sets mapping all larger elements to smaller elements within a tuple:
d = {}
for tup in tuples:
# here you may limit max(tup) to 120000
d.setdefault(min(tup), set()).add(max(tup))
# {1: {2, 3}, 2: {3}, 25: {73}}
This eliminates also all symetrical pairs: (1, 2), (2, 1).
And then search for all working combinations:
for a, bc in d.iteritems():
for b, c in it.combinations(sorted(bc), 2):
if b in d and c in d[b]:
print(a, b, c) # or yield or append to a list
Should be faster than your brute forceā¦
for a in range(1, 120000):
for b in range(a+1, 120000):
if (gcd(a, b) > 1):
continue;
for c in range(b+1, 120000):
if (gcd(a, c) = 1 and gcd(b, c) = 1):
print (a, b, c)
With N = 120000 this takes time roughly N^3/pi^2. A brute force check of all tuples takes time N^6/48, so this is much faster -- about 3 * 10^14 times faster.
Say I have an array of values:
a = np.array([1,5,4,2,4,3,1,2,4])
and three 'sum' values:
b = 10
c = 9
d = 7
Is there a way to group the values in a into groups of sets where the values combine to equal b,c and d? For example:
b: [5,2,3]
c: [4,4,1]
d: [4,2,1]
b: [5,4,1]
c: [2,4,3]
d: [4,2,1]
b: [4,2,4]
c: [5,4]
d: [1,1,2,3]
Note the sum of b,c and d should remain the same (==26). Perhaps this operation already has a name?
Here's a naive implementation using itertools
from itertools import chain, combinations
def group(n, iterable):
s = list(iterable)
return [c for c in chain.from_iterable(combinations(s, r)
for r in range(len(s)+1))
if sum(c) == n]
group(5, range(5))
yields
[(1, 4), (2, 3), (0, 1, 4), (0, 2, 3)]
Note, this probably will be very slow for large lists because we're essentially constructing and filtering through the power set of that list.
You could use this for
sum_vals = [10, 9, 7]
a = [1, 5, 4, 2, 4, 3, 1, 2, 4]
map(lambda x: group(x, a), sum_vals)
and then zip them together.