Index to closest coordinate - python

I have this function
A=[(1,2,3),(2,3,4)]
B=[(2,4,3),(1,8,1),(2,3,5),(1,5,3)]
def closestNew(A,B):
C = {}
for bp in B:
closestDist = -1
for ap in A:
dist = sum(((bp[0]-ap[0])**2, (bp[1]-ap[1])**2, (bp[2]-ap[2])**2))
if(closestDist > dist or closestDist == -1):
C[bp] = ap
closestDist = dist
return C
That will return the closest coordinate between the two lists.
Output:
{(1, 2, 3): (2, 4, 3), (2, 3, 4): (2, 3, 5)}
However, I want the index of array B (the points that matched with array A (check output)) as well in a seperate list, any ideas?
Return
idx=[0,2]

A=[(1,2,3),(2,3,4)]
B=[(2,4,3),(1,8,1),(2,3,5),(1,5,3)]
C={(1, 2, 3): (2, 4, 3), (2, 3, 4): (2, 3, 5)}
C is a dictionary where it values correspond to points on B.
idx=[] # an empty list
for x in C.values():
idx.append(B.index(x)) # index function to find the index of values in B
print(idx)
#[0, 2]

If you want to calcule the closest point to A, is better to have A as a outer loop and B as inside loop, in that way you can iterate for every A through all B's. Also you can use enumerate to know what index you are in the loop.
a = [(1,2,3),(2,3,4)]
b =[(2,4,3),(1,8,1),(2,3,5),(1,5,3)]
# store reference for the min index-point
index = []
C = {}
for indexA, ap in enumerate(a):
# Assume the max distance
closestDist = 1e9
for indexB,bp in enumerate(b):
dist = sum(((bp[0]-ap[0])**2, (bp[1]-ap[1])**2, (bp[2]-ap[2])**2))
if(dist < closestDist):
C[ap] = bp
closestDist = dist
# Initialize the list if not have value for the i-th of A
if indexA + 1 > len(index):
index.append(indexB)
else:
index[indexA] = indexB
print(index)
return C

Related

Sparse matrix subtraction

I need to write a function which gets a list of dictionaries (every dictionary represents a sparse matrix) and returns a dictionary of the subtraction matrix.
For example: for the list [{(1, 3): 2, (2, 7): 1}, {(1, 3): 6}] it needs to return {(1, 3): -4, (2, 7): 1} .
The matrices don't have to be the same size, the list can have more than two matrices and if the subtraction is 0 then it should not appear in the final dictionary.
I succeeded in getting the -4 but no matter what I write after defining x I get x == -6 and I can't tell why. I want to insert the -4 as the new value for the element.
lst = [{(1, 3): 2, (2, 7): 1}, {(1, 3): 6}]
def diff_sparse_matrices(lst):
result = {}
for dictionary in lst:
for element in dictionary:
if element not in result:
result[element] = dictionary[element]
if element in result:
x = result[element] - dictionary[element]
def diff_sparse_matrices(lst):
result = lst[0].copy()
for matrix in lst[1:]:
for coordinates, value in matrix.items():
result[coordinates] = result.get(coordinates, 0) - value
if result[coordinates] == 0:
del result[coordinates]
return result
def diff_sparse_matrices(lst):
result = lst[0].copy()
for d in lst[1:]:
for tup in d:
if tup in result:
result[tup] -= d[tup]
else:
result[tup] = -d[tup]
return result

Given a list of numbers, how many different ways can you add them together to get a sum S?

Given a list of numbers, how many different ways can you add them together to get a sum S?
Example:
list = [1, 2]
S = 5
1) 1+1+1+1+1 = 5
2) 1+1+1+2 = 5
3) 1+2+2 = 5
4) 2+1+1+1 = 5
5) 2+2+1 = 5
6) 1+2+1+1 = 5
7) 1+1+2+1 = 5
8) 2+1+2 = 5
Answer = 8
This is what I've tried, but it only outputs 3 as the answer
lst = [1, 2]
i = 1
result = 0
while i <= 5:
s_list = [sum(comb) for comb in combinations_with_replacement(lst, i)]
for val in s_list:
if val == 5:
result += 1
i+= 1
print(result)
However, this outputs three. I believe it outputs three because it doesn't account for the different order you can add the numbers in. Any ideas on how to solve this.
The problem should work for much larger data: however, I give this simple example to give the general idea.
Using both itertools.combinations_with_replacement and permutations:
import itertools
l = [1,2]
s = 5
res = []
for i in range(1, s+1):
for tup in itertools.combinations_with_replacement(l, i):
if sum(tup) == s:
res.extend(list(itertools.permutations(tup, i)))
res = list(set(res))
print(res)
[(1, 2, 2),
(2, 2, 1),
(1, 1, 2, 1),
(1, 2, 1, 1),
(2, 1, 1, 1),
(1, 1, 1, 2),
(2, 1, 2),
(1, 1, 1, 1, 1)]
print(len(res))
# 8
How about using dynamic programming? I believe it's more easy to understand and can be implemented easily.
def cal(target, choices, record):
min_choice = min(choices)
if min_choice > target:
return False
for i in range(0, target+1):
if i == 0:
record.append(1)
elif i < min_choice:
record.append(0)
elif i == min_choice:
record.append(1)
else:
num_solution = 0
j = 0
while j < len(choices) and i-choices[j] >= 0:
num_solution += record[i-choices[j]]
j += 1
record.append(num_solution)
choices = [1, 2]
record = []
cal(5, choices, record)
print(record)
print(f"Answer:{record[-1]}")
The core idea here is using an extra record array to record how many ways can be found to get current num, e.g. record[2] = 2 means we can use to ways to get a sum of 2 (1+1 or 2).
And we have record[target] = sum(record[target-choices[i]]) where i iterates over choices. Try to think, the way of getting sum=5 must be related with the way of getting sum=4 and so on.
Use Dynamic Programming.
We suppose that your list consists of [1,2,5] so we have this recursive function :
f(n,[1,2,5]) = f(n-1,[1,2,5]) + f(n-2,[1,2,5]) + f(n-5,[1,2,5])
Because if the first number in sum is 1 then you have f(n-1,[1,2,5]) options for the rest and if it is 2 you have f(n-2,[1,2,5]) option for the rest and so on ...
so start from f(1) and work your way up with Dynamic programming. this solution in the worst case is O(n^2) and this happens when your list has O(n) items.
Solution would be something like this:
answers = []
lst = [1,2]
number = 5
def f(target):
val = 0
for i in lst: #O(lst.count())
current = target - i
if current > 0:
val += answers[current-1]
if lst.__contains__(target): #O(lst.count())
val += 1
answers.insert(target,val)
j = 1;
while j<=number: #O(n) for while loop
f(j)
j+=1
print(answers[number-1])
here is a working version.
You'd want to use recursion to traverse through each possibility for each stage of addition, and pass back the numbers used once you've reached a number that is equal to the expected.
def find_addend_combinations(sum_value, addend_choices, base=0, history=None):
if history is None: history = []
if base == sum_value:
return tuple(history)
elif base > sum_value:
return None
else:
results = []
for v in addend_choices:
r = find_addend_combinations(sum_value, addend_choices, base + v,
history + [v])
if isinstance(r, tuple):
results.append(r)
elif isinstance(r, list):
results.extend(r)
return results
You could write the last part a list comprehension but I think this way is clearer.
Combinations with the elements in a different order are considered to equivalent. For example, #3 and #5 from your list of summations are considered equivalent if you are only talking about combinations.
In contrast, permutations consider the two collections unique if they are comprised of the same elements in a different order.
To get the answer you are looking for you need to combine both concepts.
First, use your technique to find combinations that meet your criteria
Next, permute the collection of number from the combination
Finally, collect the generated permutations in a set to remove duplicates.
[ins] In [01]: def combination_generator(numbers, k, target):
...: assert k > 0, "Must be a positive number; 'k = {}".format(k)
...: assert len(numbers) > 0, "List of numbers must have at least one element"
...:
...: for candidate in (
...: {'numbers': combination, 'sum': sum(combination)}
...: for num_elements in range(1, k + 1)
...: for combination in itertools.combinations_with_replacement(numbers, num_elements)
...: ):
...: if candidate['sum'] != target:
...: continue
...: for permuted_candidate in itertools.permutations(candidate['numbers']):
...: yield permuted_candidate
...:
[ins] In [02]: {candidate for candidate in combination_generator([1, 2], 5, 5)}
Out[02]:
{(1, 1, 1, 1, 1),
(1, 1, 1, 2),
(1, 1, 2, 1),
(1, 2, 1, 1),
(1, 2, 2),
(2, 1, 1, 1),
(2, 1, 2),
(2, 2, 1)}

Better ways to find pairs that sum to N

Is there a faster way to write this, the function takes a list and a value to find the pairs of numeric values in that list that sum to N without duplicates I tried to make it faster by using sets instead of using the list itself (however I used count() which I know is is linear time) any suggestions I know there is probably a way
def pairsum_n(list1, value):
set1 = set(list1)
solution = {(min(i, value - i) , max(i, value - i)) for i in set1 if value - i in set1}
solution.remove((value/2,value/2)) if list1.count(value/2) < 2 else None
return solution
"""
Example: value = 10, list1 = [1,2,3,4,5,6,7,8,9]
pairsum_n = { (1,9), (2,8), (3,7), (4,6) }
Example: value = 10, list2 = [5,6,7,5,7,5,3]
pairsum_n = { (5,5), (3,7) }
"""
Your approach is quite good, it just needs a few tweaks to make it more efficient. itertools is convenient, but it's not really suitable for this task because it produces so many unwanted pairs. It's ok if the input list is small, but it's too slow if the input list is large.
We can avoid producing duplicates by looping over the numbers in order, stopping when i >= value/2, after using a set to get rid of dupes.
def pairsum_n(list1, value):
set1 = set(list1)
list1 = sorted(set1)
solution = []
maxi = value / 2
for i in list1:
if i >= maxi:
break
j = value - i
if j in set1:
solution.append((i, j))
return solution
Note that the original list1 is not modified. The assignment in this function creates a new local list1. If you do actually want (value/2, value/2) in the output, just change the break condition.
Here's a slightly more compact version.
def pairsum_n(list1, value):
set1 = set(list1)
solution = []
for i in sorted(set1):
j = value - i
if i >= j:
break
if j in set1:
solution.append((i, j))
return solution
It's possible to condense this further, eg using itertools.takewhile, but it will be harder to read and there won't be any improvement in efficiency.
Try this, running time O(nlogn):
v = [1, 2, 3, 4, 5, 6, 7, 8, 9]
l = 0
r = len(v)-1
def myFunc(v, value):
ans = []
% this block search for the pair (value//2, value//2)
if value % 2 == 0:
c = [i for i in v if i == value // 2]
if len(c) >= 2:
ans.append((c[0], c[1]))
v = list(set(v))
l = 0
r = len(v)-1
v.sort()
while l<len(v) and r >= 0 and l < r:
if v[l] + v[r] == value:
ans.append((v[l], v[r]))
l += 1
r -= 1
elif v[l] + v[r] < value:
l += 1
else:
r -= 1
return list(set(ans))
It is called the Two pointers technique and it works as follows. First of all, sort the array. This imposes a minimum running time of O(nlogn). Then set two pointers, one pointing at the start of the array l and other pointing at its last element r (pointers name are for left and right).
Now, look at the list. If the sum of the values returned at position l and r is lower than the value we are looking for, then we need to increment l. If it's greater, we need to decrement r.
If v[l] + v[r] == value than we can increment/decrement both l or r since in any case we want to skip the combination of values (v[l], v[r]) as we don't want duplicates.
Timings: this is actually slower then the other 2 solutions. Due to the amount of combinations produced but not actually needed it gets worse the bigger the lists are.
You can use itertools.combinations to produce the 2-tuple-combinations for you.
Put them into a set if they match your value, then return as set/list:
from itertools import combinations
def pairsum_n(list1, value):
"""Returns the unique list of pairs of combinations of numbers from
list1 that sum up `value`. Reorders the values to (min_value,max_value)."""
result = set()
for n in combinations(list1, 2):
if sum(n) == value:
result.add( (min(n),max(n)) )
return list(result)
# more ugly one-liner:
# return list(set(((min(n),max(n)) for n in combinations(list1,2) if sum(n)==value)))
data = [1,2,3,4,5,6,6,5,4,3,2,1]
print(pairsum_n(data,7))
Output:
[(1, 6), (2, 5), (3, 4)]
Fun little thing, with some sorting overhead you can get all at once:
def pairsum_n2(data, count_nums=2):
"""Generate a dict with all count_nums-tuples from data. Key into the
dict is the sum of all tuple-values."""
d = {}
for n in (tuple(sorted(p)) for p in combinations(data,count_nums)):
d.setdefault(sum(n),set()).add(n)
return d
get_all = pairsum_n2(data,2) # 2 == number of numbers to combine
for k in get_all:
print(k," -> ", get_all[k])
Output:
3 -> {(1, 2)}
4 -> {(1, 3), (2, 2)}
5 -> {(2, 3), (1, 4)}
6 -> {(1, 5), (2, 4), (3, 3)}
7 -> {(3, 4), (2, 5), (1, 6)}
2 -> {(1, 1)}
8 -> {(2, 6), (4, 4), (3, 5)}
9 -> {(4, 5), (3, 6)}
10 -> {(5, 5), (4, 6)}
11 -> {(5, 6)}
12 -> {(6, 6)}
And then just access the one you need via:
print(get_all.get(7,"Not possible")) # {(3, 4), (2, 5), (1, 6)}
print(get_all.get(17,"Not possible")) # Not possible
Have another solution, it's alot faster then the one I just wrote, not as fast as #PM 2Ring's answer:
def pairsum_n(list1, value):
set1 = set(list1)
if list1.count(value/2) < 2:
set1.remove(value/2)
return set((min(x, value - x) , max(x, value - x)) for x in filterfalse(lambda x: (value - x) not in set1, set1))

Efficiently searching a pair of ordered lists with noise

Assuming two data sets are in order and that they contain pairwise matches, what is an efficient way to discover the pairs? There can be noise in either list.
From sets A,B the set C will consist of pairs (A[X1],B[Y1]),(A[X2],B[Y2]),...,(A[Xn],B[Yn]) such that X1 < X2 < ... < Xn and Y1 < Y2 < ... < Yn.
The problem can be demonstrated with the simplified Python block, where the specifics of how a successful pair is validated is irrelevant.
Because the validation condition is irrelevant, the condition return_pairs(A, B, validate) == return_pairs(B, A, validate) is not required to hold, given that the data in A,B need not be the same, just that there must exist a validation function for (A[x],B[y])
A = [0,0,0,1,2,0,3,4,0,5,6,0,7,0,0,8,0,0,9]
B = [1,2,0,0,0,0,0,3,0,0,4,0,5,6,0,0,7,0,0,8,0,9]
B1 = [1,2,0,0,0,0,0,3,0,0,4,0,5,6,0,0,7,7,7,0,0,8,0,9]
def validate(a,b):
return a and b and a==b
def return_pairs(A,B, validation):
ret = []
x,y = 0,0
# Do loops and index changes...
if validation(A[x], B[y]):
ret.append((A[x], B[y]))
return ret
assert zip(range(1,10), range(1,10)) == return_pairs(A,B,validate)
assert zip(range(1,10), range(1,10)) == return_pairs(A,B1,validate)
Instead of iterating each list in two nested loops you can first remove the noise according to your own criteria, then create a third list with the filtered elements and run each item (being a newly formed tuple) of the list against your validation. This is assuming I understood the question correctly, which I think I didn't really:
Demo
A = [0,0,0,1,2,0,3,4,0,5,6,0,7,0,0,8,0,0,9]
B = [1,2,0,0,0,0,0,3,0,0,4,0,5,6,0,0,7,0,0,8,0,9]
def clean(oldList):
newList = []
for item in oldList:
if 0<item and (not newList or item>newList[-1]):
newList.append(item)
return newList
def validate(C):
for item in C:
if item[0] != item[1]:
return False
return True
C = zip(clean(A),clean(B))
#clean(A):[1, 2, 3, 4, 5, 6, 7, 8, 9]
#clean(B):[1, 2, 3, 4, 5, 6, 7, 8, 9]
#list(C):[(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8, 8), (9, 9)]
#validate(C): True
A solution. O(n2)
def return_pairs(A,B, validation):
ret = []
used_x, used_y = -1,-1
for x, _x in enumerate(A):
for y, _y in enumerate(B):
if x <= used_x or y <= used_y:
continue
if validation(A[x], B[y]):
used_x,used_y = x,y
ret.append((A[x], B[y]))
return ret

Get n in exact k parts. Recursion and partition algorithm. p(n,k)

I'm looking to enumerate all the partitions of n in k parts.
So for p(5,3) i'd get 2 partitions of k = 3 => (3,1,1), (2,2,1).
Here's what I found from searching and looking through stackoverflow :
def p(n,k):
lst = []
if n < k:
return lst
elif k == 1:
return lst
elif k == n:
return lst
else:
p(n-1, k-1)
p(n-k, k)
return lst
^^^^ This is the form i want,
As it is, finding the sum of k parts is easy, you return p(n-1, k-1) + p(n-k,k). As for me, I need to list each element like so [(3,1,1), (2,2,1)].
My main problem is to "build" those partitions recursively. How would you tackle this?
Edit
If you get base case k = 1, add + 1, k-1 times. (4,1) then (4,1,1)
If you get base case k = n, split up and remove one to each part.
Like so : (3,3) then (3,3,3) then (2,2,2)
If you get base case k < n, nothing
Basically, my problem is to "stack" up the ones from base case to top and get a complete list p(6,3) = [(2,2,2), (4,1,1), (3,2,1)]
I would add to the recursive function a third parameter m which is the maximum value an element can have in the partition. Then I would define the function like this:
def p(n, k, m=None):
if m is None:
m = n - k + 1 # maximum can be n - k + 1 since minimum is 1
if k == 0:
if n == 0:
yield ()
return
for i in xrange(1, m + 1): # first could be from 1 to the maximum
# the rest of the sum will be n - i among k - 1 elements with
# maximum i
for t in p(n - i, k - 1, i):
yield (i, ) + t
Examples:
>>> list(p(10, 3))
[(4, 3, 3), (4, 4, 2), (5, 3, 2), (5, 4, 1), (6, 2, 2), (6, 3, 1), (7, 2, 1), (8 , 1, 1)]
>>> list(p(6, 2))
[(3, 3), (4, 2), (5, 1)]

Categories