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
Related
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.
If I have this simple code, how can I display all available variants ?
#Display all possible variants until reach input sum with coins of 2 and 5
#Not fixed: Output only first result !
#Input
summ = int(input("Enter sum: "))
two = 2
five = 5
#Calculations/Checks/Output
for i in range(0, two+1):
for j in range(0, five+1):
if (i*2 + j*5 == summ):
print(i, "*2 + ", j, "*5 = ", summ)
#End
For example:
Input: 17
Output:
1*2 + 3*5 = 17
6*2 + 1*5 = 17
But the code displays only the first result?
How can I fix this ?
Change the inputs of range:
summ = int(input("Enter sum: "))
two = 2
five = 5
for i in range(summ//two+1):
for j in range(summ//five+1):
if (i*2 + j*5 == summ):
print(i, "* 2 +", j, "* 5 =", summ)
You can use itertools, and a generator:
In [17]: def correct_sum_i(i, val):
...: sum_perm = [comb for comb in itertools.combinations_with_replacement([2,5],i) if sum(comb) == val]
...: return sum_perm[0] if sum_perm else None
...:
In [18]: val = 14
In [19]: next(correct_sum_i(i,val) for i in range(1000) if correct_sum_i(i, val))
Out[19]: (2, 2, 5, 5)
Edit: You probably also want to check for pathological cases where this is not possible, like 1,3 etc....
Edit: all sums
In [50]: def all_sums(char_set, sum_value):
...: def correct_sum_i(i):
...:
...: sum_perm = [comb for comb in itertools.combinations_with_replacement(char_set,i) if sum(comb) == sum_value]
...: return sum_perm if sum_perm else None
...:
...: assert min(char_set) > 0
...:
...: return list(correct_sum_i(i) for i in range(int(sum_value / min(char_set))+ 1) if correct_sum_i(i))
...:
In [51]: print (all_sums([2,5], 20))
[[(5, 5, 5, 5)], [(2, 2, 2, 2, 2, 5, 5)], [(2, 2, 2, 2, 2, 2, 2, 2, 2, 2)]]
this also gives you the desired behaviour for your case:
In [53]: print (all_sums([2,5], 17))
[[(2, 5, 5, 5)], [(2, 2, 2, 2, 2, 2, 5)]]
My question is how to find the maximum length of consecutive repeated numbers (or elements in general) in a list. I wrote the following function which works fine but I was wondering if there's a better way to do this or improve my code.
def longest(roll):
'''Return the maximum length of consecutive repeated elements in a list.'''
i = 0
M = 0 # The maximum length
while 0 <= i < len(roll):
c = 1 # Temporarily record the length of consecutive elements
for j in range(i+1, len(roll)):
if roll[j] != roll[i]:
i = j
break
c += 1
i += 1
if c > M:
M = c
if i == len(roll) - 1:
break
return M
By maximum length I mean the following:
[1, 1, 2, 2, 2, 4] should return 3 (2 repeated 3 times);
[1, 2, 1, 2, 1] should return 1 (1 and 2 only repeated once).
You can use itertools.
In [8]: import itertools
In [9]: z = [(x[0], len(list(x[1]))) for x in itertools.groupby(a)]
In [10]: z
Out[10]: [(1, 2), (2, 3), (3, 1)]
Tuples are in (item, count) format. If there are multiple runs of a given number, this will group them accordingly as well. See below.
In [11]: a = [1,1,1,1,1,2,2,2,2,2,1,1,1,3,3]
In [12]: z = [(x[0], len(list(x[1]))) for x in itertools.groupby(a)]
In [13]: z
Out[13]: [(1, 5), (2, 5), (1, 3), (3, 2)]
Getting the max value isn't that hard from here.
In [15]: max(z, key=lambda x:x[1])[1]
Out[15]: 5
longest_fragment = 0
current_fragment = 0
a = int(input())
last_input = a # why do I assign last_input here?
while a:
if a == last_input:
current_fragment += 1
else: # why is current_fragment assigned 1 in this clause?
if current_fragment > longest_fragment:
longest_fragment = current_fragment
current_fragment = 1
last_input = a
a = int(input())
longest_fragment = max(longest_fragment, current_fragment)
# why didn't i use max in the loop?
# why am I checking again down here anyway?
print('The longest fragment was:', longest_fragment)
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.
The challenge was to find all possible combinations of numbers less than N whose sum equals N.
For instance, when N is equal to:
2
1+1 - 1 way
3
2+1
1+1+1 - 2 ways
4
3+1
2+2
2+1+1
1+1+1+1 - 4 ways
and so on...
Now creating it in python, to understand the pattern I drafted this code 1st:
N=5
for d in drange(0,N,1):
if N-d*4>=0:
for c in drange(0,N,1):
if N-d*4-c*3>=0:
for b in drange(0,N,1):
if N-d*4-c*3-b*2>=0:
for a in drange(0,N,1):
if N-d*4-c*3-b*2-a*1==0:
if sum([d,c,b,a])!=1:
print d,c,b,a
else: break
else:break
else:break
Then I changed the code to this where this worked for N = 6 and below:
N=6
for e in drange(0,N,1):
if N-e*5>=0:
C0 = N-e*5
for d in drange(0,N,1):
if C0-d*4>=0:
C1 = C0-d*4
for c in drange(0,N,1):
if C1-c*3>=0:
C2 = C1-c*3
for b in drange(0,N,1):
if C2-b*2>=0:
C3 = C2-b*2
for a in drange(0,N,1):
if C3-a*1==0:
if sum([e,d,c,b,a])!=1:
print e,d,c,b,a
else: break
else:break
else:break
else:break
Next Version incorporated arrays to keep track of numbers and save computation space:
N=6
Nums = drange2(6-1,-1,-1)
Vals = [0]*6
Vars = [0]*6
for Vars[0] in drange(0,N,1):
if N-Vars[0]*Nums[0]>=0:
Vals[0] = N-Vars[0]*Nums[0]
for Vars[1] in drange(0,N,1):
if Vals[0]-Vars[1]*Nums[1]>=0:
Vals[1] = Vals[0]-Vars[1]*Nums[1]
for Vars[2] in drange(0,N,1):
if Vals[1]-Vars[2]*Nums[2]>=0:
Vals[2] = Vals[1]-Vars[2]*Nums[2]
for Vars[3] in drange(0,N,1):
if Vals[2]-Vars[3]*Nums[3]>=0:
Vals[3] = Vals[2]-Vars[3]*Nums[3]
for Vars[4] in drange(0,N,1):
if Vals[3]-Vars[4]*Nums[4]==0:
if sum([Vars[0],Vars[1],Vars[2],Vars[3],Vars[4]])!=1:
print Vars
else: break
else:break
else:break
else:break
Then I thought to make this code functional where N is 100, I made it recursive...
N=48
Nums = drange2(N-1,-1,-1)
Vals = [0]*N
Vars = [0]*(N-1)
count=0
def sumCombos(Number,i):
if i==0:
global count
for Vars[i] in xrange(0,i+2,1):
z = Number-Vars[i]*Nums[i]
if z>=0:
Vals[i] = z
sumCombos(Number,i+1)
else: break
elif i<Number-2:
for Vars[i] in xrange(0,i+1,1):
z = Vals[i-1]-Vars[i]*Nums[i]
if z >=0:
Vals[i]=z
sumCombos(Number,i+1)
else: break
elif i==Number-2:
for Vars[i] in xrange(0,i+3,1):
if Vals[i-1]-Vars[i]*Nums[i]==0:
count+=1
sumCombos(N,0)
print count
PROBLEM: It takes too much time because of 1000000+ method calls, so is there a way I can make this iterative where it creates that previous cascade effect without me typing that all? I searched the website and others on how to make a recursive function involving for-loops and if statements iterative, but no luck with this particular one. Please offer any wisdom -- Shaha3
Why do you want it to be recursive?
>>> from itertools import chain, combinations_with_replacement
>>> n = 7
>>> [i for i in chain.from_iterable(
combinations_with_replacement(range(1, n), k)
for k in range(2, n+1))
if sum(i) == n]
[(1, 6), (2, 5), (3, 4), (1, 1, 5), (1, 2, 4), (1, 3, 3), (2, 2, 3), (1, 1, 1, 4), (1, 1, 2, 3), (1, 2, 2, 2), (1, 1, 1, 1, 3), (1, 1, 1, 2, 2), (1, 1, 1, 1, 1, 2), (1, 1, 1, 1, 1, 1, 1)]
This problem grows with n! so, it'll take a lot of time for big numbers.
I guess you are talking about integer partitioning problem (wiki: http://en.wikipedia.org/wiki/Partition_(number_theory) ) It can be done either an iterative way or a recursive way, though there could be a depth limit on the recursive method. Here are my implementations
def partitions(n):
def next(seq):
L = len(seq)
## start from L-2 element, must have at least one element in suffix
for i in range(L-2, -1, -1):
if seq[i-1] and seq[i-1] > seq[i]: break
remainder = n - sum(seq[:i+1]) - 1
return seq[:i] + [seq[i]+1] + [1 for _ in range(remainder)]
start, end = [1 for _ in range(n)], [n]
seq = start
while True:
yield seq
if seq >= end: break
seq = next(seq)
# test cases
if __name__ == '__main__':
## test partitions
assert list(partitions(4)) == [[1, 1, 1, 1], [2, 1, 1], [2, 2], [3, 1], [4]]
assert list(partitions(5)) == [
[1, 1, 1, 1, 1],
[2, 1, 1, 1], [2, 2, 1],
[3, 1, 1], [3, 2],
[4, 1],
[5]]
print 'all tests passed'