Numba save permutations with duplicates - python

I have a function that gets called extremely often and so to speed it up i want to use numbas #njit decorator. However in this function i need to calculate the permutations of an array and numba does not play nice with itertools.
I found this for a numba save version to produce permutations however this implementation does not deal with duplicates in the input in the way i need it to.
array1 = [9,9,21]
def permutations(A, k):
r = [[i for i in range(0)]]
for i in range(k):
r = [[a] + b for a in A for b in r if (a in b)==False]
return r
print(permutations(array1,3))
print(list(itertools.permutations(array1,3)))
[]
[(9, 9, 21), (9, 21, 9), (9, 9, 21), (9, 21, 9), (21, 9, 9), (21, 9, 9)]
What i want is the second result, not the first

I've created your "ideal world" permutations function, it recursively sends one permutation of the original list with one member short.
However, don't expect as fast results as in itertools.
array1 = [9, 9, 21]
array2 = [1, 2, 3]
array3 = [1, 2, 3, 4]
def permutations(A):
r = []
for i in range(len(A)):
a, b = A[i], A[: i] + A[i + 1:]
if b:
for c in permutations(b):
if [a] + c in r:
continue
r.append([a] + c)
else:
r.append([a])
return r
print(permutations(array1))
print(permutations(array2))
print(permutations(array3))
OUTPUT:
[[9, 9, 21], [9, 21, 9], [21, 9, 9]]
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
[[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], [1, 4, 2, 3], [1, 4, 3, 2],
[2, 1, 3, 4], [2, 1, 4, 3], [2, 3, 1, 4], [2, 3, 4, 1], [2, 4, 1, 3], [2, 4, 3, 1],
[3, 1, 2, 4], [3, 1, 4, 2], [3, 2, 1, 4], [3, 2, 4, 1], [3, 4, 1, 2], [3, 4, 2, 1],
[4, 1, 2, 3], [4, 1, 3, 2], [4, 2, 1, 3], [4, 2, 3, 1], [4, 3, 1, 2], [4, 3, 2, 1]]

Related

Stack every two elements of the third dimension in a numpy 3d array

I have a numpy array of shape (294, 62, 350). Along the third dimension (the 350), I need to combine every two columns into one longer one which would result in an array of shape (294, 124, 175). For example if I have this array:
a_3d_array = np.array([[[1, 2, 3, 6, 1, 2], [3, 4, 3, 6, 1, 4]],
[[5, 2, 2, 1, 4, 2], [2, 9, 4, 3, 2, 7]]])
The expected output would be:
expected_output = np.array([[[5, 2, 4], [2, 4, 2], [ 2, 1, 2], [9, 3, 7]],
[[1, 3, 1], [3, 3, 1], [2, 6, 2], [4, 6, 4]]])
Sorry as I'm new to python and I don't have a clue how to approach this and thus I don't have a "my own attempt" to include here.
a_3d_array = np.array([[[1, 2, 3, 6, 1, 2], [3, 4, 3, 6, 1, 4]],
[[5, 2, 2, 1, 4, 2], [2, 9, 4, 3, 2, 7]]])
output = np.hstack([a_3d_array[:, :, ::2], a_3d_array[:, :, 1::2]])
To combine every N-th column:
N = 3
output = np.hstack([an_array[:, :, idx::N] for idx in range(N)])
You can reshape and reverse the first dimension:
a_3d_array.reshape((2,4,3), order='F')[::-1]
If you don't know the shape:
x,y,z = a_3d_array.shape
a_3d_array.reshape((x,y*2,-1), order='F')[::-1]
output:
array([[[5, 2, 4],
[2, 4, 2],
[2, 1, 2],
[9, 3, 7]],
[[1, 3, 1],
[3, 3, 1],
[2, 6, 2],
[4, 6, 4]]])

Form groups in a list based on condition

(Edited based on feedbacks)
I've got a list like this:
my_list = [1,2,3,1,2,4,1,3,5,1,4,6,1,4,7]
That I'm struggling to turn into that:
result = [[1,2,3,1,2,4],[1,3,5],[1,4,6,1,4,7]]
I want to group my_list elements in sublists of 3 elements unless my_list[i] = my_list[i+3] in this case I want to merge those in bigger sublists.
Here is what I've tried:
result = []
for i in range(1,len(my_list),3):
try:
print(my_list[i],my_list[i+3])
if my_list[i] == my_list[i+3]:
result.extend(my_list[i-1:i+5])
else:
result.append(my_list[i-1:i+2])
FWIW, the description of your logic isn't quite clear. However, if I understand your code correctly, I think this is at least something in the correct direction:
def stepper(my_list, step, bigger_step):
res = []
idx = 0
while idx <= len(my_list)-1:
if idx + step > len(my_list)-1:
# Remove this append if you don't want the "leftovers"
res.append(my_list[idx:])
break
if my_list[idx] != my_list[idx+step]:
res.append(my_list[idx:idx+step])
idx += step
else:
res.append(my_list[idx:idx+bigger_step])
idx += bigger_step
return res
my_list = [1,2,3,1,2,4,1,3,5,1,3,6,1,2,7]
print(stepper(my_list, step=3, bigger_step=6)) # Output: [[1, 2, 3, 1, 2, 4], [1, 3, 5, 1, 3, 6], [1, 2, 7]]
Note that the above output is different from your given example, because of your given logic that you've provided makes the second sub-list extended as well as the first.
Using the above code, we can check the results if we change bigger_step easily with a for-loop:
for big in range(4, 10):
print(f"Step: 3, Bigger_Step: {big}, Result:{stepper(my_list, step=3, bigger_step=big)}")
Output:
Step: 3, Bigger_Step: 4, Result:[[1, 2, 3, 1], [2, 4, 1], [3, 5, 1, 3], [6, 1, 2], [7]]
Step: 3, Bigger_Step: 5, Result:[[1, 2, 3, 1, 2], [4, 1, 3], [5, 1, 3], [6, 1, 2], [7]]
Step: 3, Bigger_Step: 6, Result:[[1, 2, 3, 1, 2, 4], [1, 3, 5, 1, 3, 6], [1, 2, 7]]
Step: 3, Bigger_Step: 7, Result:[[1, 2, 3, 1, 2, 4, 1], [3, 5, 1, 3, 6, 1, 2], [7]]
Step: 3, Bigger_Step: 8, Result:[[1, 2, 3, 1, 2, 4, 1, 3], [5, 1, 3], [6, 1, 2], [7]]
Step: 3, Bigger_Step: 9, Result:[[1, 2, 3, 1, 2, 4, 1, 3, 5], [1, 3, 6, 1, 2, 7]]

How to return indices from sorting a 2d numpy array row-by-row?

Input: A 2D numpy array
Output: An array of indices that will sort the array row by row (or column by column)
E.g.: Say the function is get_sorted_indices(array, axis=0)
a = np.array([[1,2,3,4,5]
,[2,3,4,5,6]
,[1,2,3,4,5]
,[2,3,4,6,6]
,[2,3,4,5,6]])
ind = get_sorted_indices(a, axis=0)
Then we will get
>>> ind
[0, 2, 1, 4, 3]
>>> a[ind] # should be equals to a.sort(axis = 0)
array([[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[2, 3, 4, 5, 6],
[2, 3, 4, 6, 6]])
>>> a.sort(axis=0)
array([[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[2, 3, 4, 5, 6],
[2, 3, 4, 6, 6]])
I've looked at argsort but I don't understand its output and reading the documentation doesn't help:
>>> a.argsort()
array([[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]])
>>> a.argsort(axis=0)
array([[0, 0, 0, 0, 0],
[2, 2, 2, 2, 2],
[1, 1, 1, 1, 1],
[3, 3, 3, 4, 3],
[4, 4, 4, 3, 4]])
I can do this manually but I think I'm misunderstanding argsort or I'm missing something from numpy.
Is there a standard way to do this or I have no choice but to do this manually?

How to create a list from tuples with sub-tuples?

I have two lists a and b. Then I create all combinations taking all two-length combinations of a plus one each of b:
import itertools as it
a = [1,2,3,4]
b = [5,6]
for i in it.product(it.combinations(a, 2), b):
print (i)
# output:
((1, 2), 5)
((1, 2), 6)
((1, 3), 5)
...
# expected output:
[1, 2, 5]
[1, 2, 6]
[1, 3, 5]
...
How can the tuples be transformed at the stage of the loop operation into lists?
The following comprehensions will work:
>>> [[*x, y] for x, y in it.product(it.combinations(a, 2), b)] # Py3
>>> [list(x) + [y] for x, y in it.product(it.combinations(a, 2), b)] # all Py versions
[[1, 2, 5],
[1, 2, 6],
[1, 3, 5],
[1, 3, 6],
[1, 4, 5],
[1, 4, 6],
[2, 3, 5],
[2, 3, 6],
[2, 4, 5],
[2, 4, 6],
[3, 4, 5],
[3, 4, 6]]
Simplified approach:
a = [1,2,3,4]
b = [5,6]
l = len(a)
print(sorted([a[i], a[i_n], j] for i in range(l) for j in b
for i_n in range(i+1, l) if i < l-1))
The output:
[[1, 2, 5], [1, 2, 6], [1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6], [3, 4, 5], [3, 4, 6]]

Find all possible combinations/partitions of 2 numbers for a given number

I found this code on the Internet (Find all possible subsets that sum up to a given number)
def partitions(n):
if n:
for subpart in partitions(n-1):
yield [1] + subpart
if subpart and (len(subpart) < 2 or subpart[1] > subpart[0]):
yield [subpart[0] + 1] + subpart[1:]
else:
yield []
I was wondering if someone could find a way to pull out of the answer only the answers, that are 2 digit addition?
For example: I type in 10. It gives me:
[[1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 2], [1, 1, 1, 1, 1, 1, 2, 2], [1, 1, 1, 1, 2, 2, 2], [1, 1, 2, 2, 2, 2], [2, 2, 2, 2, 2], [1, 1, 1, 1, 1, 1, 1, 3], [1, 1, 1, 1, 1, 2, 3], [1, 1, 1, 2, 2, 3], [1, 2, 2, 2, 3], [1, 1, 1, 1, 3, 3], [1, 1, 2, 3, 3], [2, 2, 3, 3], [1, 3, 3, 3], [1, 1, 1, 1, 1, 1, 4] , [1, 1, 1, 1, 2, 4], [1, 1, 2, 2, 4], [2, 2, 2, 4], [1, 1, 1, 3, 4], [1, 2, 3, 4], [3, 3, 4], [1, 1, 4, 4], [2, 4, 4], [1, 1, 1, 1, 1, 5], [1, 1, 1, 2, 5], [1, 2, 2, 5], [1, 1, 3, 5], [2, 3, 5], [1, 4, 5], [5, 5], [1, 1, 1, 1, 6], [1, 1, 2 , 6], [2, 2, 6], [1, 3, 6], [4, 6], [1, 1, 1, 7], [1, 2, 7], [3, 7], [1, 1, 8], [2, 8], [1, 9], [10]]
I would like it only gives:
[[5, 5], [4, 6], [3, 7], [2, 8], [1, 9]]
Since you only want partitions of length 2 (and the products of the elements of each partition), we can use a simpler approach:
#! /usr/bin/env python
''' Find pairs of positive integers that sum to n, and their product '''
def part_prod(n):
parts = [(i, n-i) for i in xrange(1, 1 + n//2)]
print parts
print '\n'.join(["%d * %d = %d" % (u, v, u*v) for u,v in parts])
def main():
n = 10
part_prod(n)
if __name__ == '__main__':
main()
output
[(1, 9), (2, 8), (3, 7), (4, 6), (5, 5)]
1 * 9 = 9
2 * 8 = 16
3 * 7 = 21
4 * 6 = 24
5 * 5 = 25
You could use itertools.combinations_with_replacement
from itertools import combinations_with_replacement
n = 10
print([x for x in combinations_with_replacement(range(1,n), 2) if sum(x) == n])
[(1, 9), (2, 8), (3, 7), (4, 6), (5, 5)]
Just for fun with list comprehension without using itertools.
num = 10
[[x, y] for x in range(1, num) for y in range(1, num) if x + y == num and x <= y]
# [[1, 9], [2, 8], [3, 7], [4, 6], [5, 5]]

Categories

Resources