How to maximise addition/subtraction combinations? - python

Suppose I have a list of 10 elements [a, b, c, d, e, f, g, h, i, j] and I can multiply each element by 0, 1, 2, -1, -2.
The total of the multiplication factors I use must be equal to zero. Ie if I multiply five numbers by -1 I must multiply the other five by 1, or I can multiply a by 2, b and c by -1 and the rest by 0.
I want to find the list resulting from this operation that has the largest sum.
How can I go about coding this in python?
I've tried coding every single iteration of [2, 1, 0, -1, -2] and deleting the lists that do not add to 0 and then multiplying by the original list, however I got stuck.

You can sort the list, scan it from the ends towards the center, assigning 2 to the larger element and -2 to the smaller.
def baby_knapsack(xs):
xs = sorted(xs, reverse=True)
res = list()
n = len(xs)
for i in range(n//2):
res.extend(((xs[i], 2), (xs[-1-i], -2)))
if n % 2 == 1:
res.append((xs[n//2], 0))
return res
xs = [-10, -5, 0, 5, 10, 15]
# In [73]: q.baby_knapsack(q.xs)
# Out[73]: [(15, 2), (-10, -2), (10, 2), (-5, -2), (5, 2), (0, -2)]

Related

Why is the last element repeating?

I'm trying to find the diagonal and counter diagonal elements for a given list. The function is written below:
def diagonalDifference(arr):
side_1=0
side_2 =0
for row in arr:
for column in row:
if(arr.index(row)==row.index(column)):
side_1+=column
if(arr.index(row)+row.index(column)==(len(arr)-1)):
print(arr.index(row),row.index(column)) #(1)index for counter diagonal
side_2+=column
return(abs(side_1-side_2))
Edit: The values passed are:
(-1 1 -7 -8),
(-10 -8 -5 -2),
(0 9 7 -1),
(4 4 -2 1)
The result of (1) is:
(0,3),
(1,2),
(2,1),
(3,0),
(3,0)
The repeated values 4, 4 in the position [3][0],[3][1] is generating the problem
As you've noted, with repeating values, your index lookup fails. You are also iterating over the every value instead of just the ones you want (the diagonals). Rather than taking the entries of the list and then finding their index (with index method), just use the indices to start with.
>>> a = ((-1, 1, -7, -8), (-10, -8, -5, -2), (0, 9, 7, -1), (4, 4 ,-2, 1))
>>> d1 = d2 = 0
>>> dim = len(a)
>>> for i in range(dim):
... d1 += a[i][i]
... d2 += a[i][dim-i-1]
...
>>> print(d1, d2)
-1 0
You may want some validation that all the lists are the same length and that the array is square, but if you can assume that, this should be ok.

Change an array of integers into binary array

I have multiple arrays, each contain 6 integer values. eg x[0. 1. 0. 2. 1. 2.] i want to convert each value in each array into binary array e.g. x_bin[0,0, 0,1, 0,0, 1,0, 0,1, 1,0]. Note that initially my variable has 6 integer (from 0 - 2), i want my final result to contain 12 values (2 bits for each integer).
Thank you in advance.
Convert each number to binary, then convert each binary digit to an integer.
>>> x = [0, 1, 0, 2, 1, 2]
>>> [tuple(int(c) for c in '{:02b}'.format(i)) for i in x]
[(0, 0), (0, 1), (0, 0), (1, 0), (0, 1), (1, 0)]

Check from how many combinations in a list you can create a triangle

I'm writing a Python program that returns out of how many combinations in a list you can create a triangle.
Example:
--> test([1,1,3])
0 #you cant make a triangle out of 1,1,3 (the only combination in this list)
--> test([2,789,5,3,3237,4])
3 #you can make a triangle out of [2,5,4],[5,3,4] and [2,4,3]
I only managed to write a function that checks if you can create a triangle out of 3 given edges:
def check(a,b,c):
n = max((a,b,c))
x = 0
y = 0
for i in [a,b,c]:
if i != n:
if x == 0:
x = i
elif y == 0:
y = i
return (x+y)>n
This is quite easy with the function to check if any three sides can make a triangle, check, given by you in the comments:
from itertools import combinations
def test(x):
return sum(check(*comb) for comb in combinations(x, 3))
This uses the fact that itertools.combinations gives all possible combinations, here of length 3 of the input, and the fact that bools are integers with True == 1 and False == 0, so we can just sum them to get the number of True elements.
Your check function could also be more explicit:
def check(a, b, c):
a, b, c = sorted([a, b, c])
return a + b > c
Firstly, your check function is incorrect. From this post, we see that the conditions required are that the sum of each pair of sides is greater than the other side. As #david explained:
Let's say that a, b, c is the sides of the triangle. Therefore, it
must be satisfy this criteria:
a + b > c
a + c > b
b + c > a
You are only checking to see if the sum of the two smaller sides is greater than the largest. Furthermore, your function would fail for cases where the largest side is duplicated. For example, the values 1, 4, 4 form a valid triangle but your function check(1, 4, 4) returns False.
That being said, there is very little you can do to avoid checking all combinations of 3 values.
from itertools import combinations
[(x, y, z) for (x, y, z) in combinations(test, 3)
if ((x+y) > z) and ((x+z) > y) and ((y+z) > x)]
#[(2, 5, 4), (2, 3, 4), (5, 3, 4)]
You could make a marginal speed improvement by sorting the list. This helps because the code can short-circuit because the first condition will fail (and you don't have to check the other two).
For example, these are the sorted combinations of 3 sides from your example list:
>>> test = [2,789,5,3,3237,4]
>>> list(combinations(sorted(test), 3))
[(2, 3, 4),
(2, 3, 5),
(2, 3, 789),
(2, 3, 3237),
(2, 4, 5),
(2, 4, 789),
(2, 4, 3237),
(2, 5, 789),
(2, 5, 3237),
(2, 789, 3237),
(3, 4, 5),
(3, 4, 789),
(3, 4, 3237),
(3, 5, 789),
(3, 5, 3237),
(3, 789, 3237),
(4, 5, 789),
(4, 5, 3237),
(4, 789, 3237),
(5, 789, 3237)]
In the third example, x = 2, y = 3, and z = 789. The first condition (x+y) > z will fail and you won't have to check the other two. I've included some timing results to show that sorting is slightly faster.
Update
If you wanted to avoid duplicates, you can use a set comprehension:
{(x, y, z) for (x, y, z) in combinations(sorted(test), 3) if
((x+y) > z) and ((x+z) > y) and ((y+z) > x)}
Timing Results
# make list of random numbers
import numpy as np
N = 100
test = [np.random.randint(0,5000) for i in range(N)]
# without sorting
%%timeit
[(x, y, z) for (x, y, z) in combinations(test, 3)
if ((x+y) > z) and ((x+z) > y) and ((y+z) > x)]
#10 loops, best of 3: 76.1 ms per loop
# with sorting
%%timeit
[(x, y, z) for (x, y, z) in combinations(sorted(test), 3) if
((x+y) > z) and ((x+z) > y) and ((y+z) > x)]
#10 loops, best of 3: 65.1 ms per loop

python's lists ,tuples and for loop

i have a list :
a=[1, 2, 3, 300] # this is IDs of workers
And a list of tuples :
f=[(1, 1, 1), (1, 0, 0), (0, 0, 0), (1, 500, 600)]
For every element in a ( a[i]) it has a related element (tuple) in f ( f[i) ) . So what i need is to sum the elements in f[i] for every a[i] till certain indices according to user . For example if user want the summation to end till certain index say 2 , the output will then be for ID 1=a[0] --> sum will be 2 (f[0]=1 +f[1]=1 ) , for ID 2=a[2] --> the summation is 1 [f[0]=0+f[1]=1] and so on till a[3]
here is my code :
str1=int(input('enter the index[enter -->1/2/3]'))
a=[1, 2, 3, 300]
f=[(1, 1, 1), (1, 0, 0), (0, 0, 0), (1, 500, 600)]
length=len(a)
temp=0 #sum
for i in range(0,length):
y=a[i]
att_2=f[i]
print("{} {}".format("The worker ID is ", y))
for z in range(0,(str1)):
temp=temp+att_2[i]
print(temp) # tracing the sum
I getting a error plus wrong result for some a[i] :
enter the index[enter -->1/2/3]2
temp=temp+att_2[i]
IndexError: tuple index out of range
The Student ID is 1
1
2
The Student ID is 2
2
2
The Student ID is 3
2
2
The Student ID is 300
Process finished with exit code 1
I am trying to fix these errors , but i cannot find its reasons. Thank you
Your Error is because you have mixed up the variable i and the variable z.
Your code loops through the tuple using variable i and that will result in an error as the maximum value i will take is calculated for another set of instructions.
A switch of variables on line 11 will fix your problems
Original:
str1=int(input('enter the index[enter -->1/2/3]'))
a=[1, 2, 3, 300]
f=[(1, 1, 1), (1, 0, 0), (0, 0, 0), (1, 500, 600)]
length=len(a)
temp=0 #sum
for i in range(0,length):
y=a[i]
att_2=f[i]
print("{} {}".format("The worker ID is ", y))
for z in range(0,(str1)):
temp=temp+att_2[i]
print(temp) # tracing the sum
New:
str1=int(input('enter the index[enter -->1/2/3]'))
a=[1, 2, 3, 300]
f=[(1, 1, 1), (1, 0, 0), (0, 0, 0), (1, 500, 600)]
length=len(a)
temp=0 #sum
for i in range(0,length):
y=a[i]
att_2=f[i]
print("{} {}".format("The worker ID is ", y))
for z in range(0,(str1)):
temp=temp+att_2[z]
print(temp) # tracing the sum

Python, finding neighbors in a 2-d list

So here's the issue, I have a 2-d list of characters 'T' and 'F', and given coordinates I need to get all of its neighbors. I have this:
from itertools import product, starmap
x, y = (5, 5)
cells = starmap(lambda a, b: (x + a, y + b), product((0, -1, +1), (0, -1, +1)))
from determining neighbors of cell two dimensional list But it will only give me a list of coordinantes, so i still fetch the values afterwords. I'd like the search and retrieval done in one step, so findNeighbors(5,5) would return F,T,F,F,... instead of (5, 4), (5, 6), (4, 5), (4, 4)... Is there a fast way of doing this? The solutin can include a structure other than a list to hold the initial information
The following should work, with just a minor adaptation to the current code:
from itertools import product, starmap, islice
def findNeighbors(grid, x, y):
xi = (0, -1, 1) if 0 < x < len(grid) - 1 else ((0, -1) if x > 0 else (0, 1))
yi = (0, -1, 1) if 0 < y < len(grid[0]) - 1 else ((0, -1) if y > 0 else (0, 1))
return islice(starmap((lambda a, b: grid[x + a][y + b]), product(xi, yi)), 1, None)
For example:
>>> grid = [[ 0, 1, 2, 3],
... [ 4, 5, 6, 7],
... [ 8, 9, 10, 11],
... [12, 13, 14, 15]]
>>> list(findNeighbors(grid, 2, 1)) # find neighbors of 9
[8, 10, 5, 4, 6, 13, 12, 14]
>>> list(findNeighbors(grid, 3, 3)) # find neighbors of 15
[14, 11, 10]
For the sake of clarity, here is some equivalent code without all of the itertools magic:
def findNeighbors(grid, x, y):
if 0 < x < len(grid) - 1:
xi = (0, -1, 1) # this isn't first or last row, so we can look above and below
elif x > 0:
xi = (0, -1) # this is the last row, so we can only look above
else:
xi = (0, 1) # this is the first row, so we can only look below
# the following line accomplishes the same thing as the above code but for columns
yi = (0, -1, 1) if 0 < y < len(grid[0]) - 1 else ((0, -1) if y > 0 else (0, 1))
for a in xi:
for b in yi:
if a == b == 0: # this value is skipped using islice in the original code
continue
yield grid[x + a][y + b]

Categories

Resources