I have list a:
a = [0,1,2,3,4,5]
Then I create all three-element combinations of this list. The results are grouped in sublistach because of matching to the equivalent in the form of a binary 3-bit string. For example, the result [0,4,5] corresponds to the sequence 001, because each even number corresponds to 0, and the odd number 1.
The code I use with the comments:
import itertools as it
import itertools
# I create three-element combinations of zeros and ones
combinations_3bit = list(map(list, itertools.product([0,1], repeat=3)))
# output: [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
# I create a list of strings with values from the list `3bit_combinations`
a=[]
for i in range(len(combinations_3bit)):
a2 =''.join(map(str, [1 if x%2 else 0 for x in combinations_3bit[i]]))
a.append(a2)
# output: ['000', '001', '010', '011', '100', '101', '110', '111']
# I remove repetitions in pairs of type 001 with 100, 011 with 110, etc.
combinations_3bit_without_repetition = [v for k, v in enumerate(a) if v[::-1] not in a[:k]]
# output: ['000', '001', '010', '011', '101', '111']
b = [0,1,2,3,4,5]
good = []
for i in range(len(combinations_3bit_without_repetition)):
c=[]
for u in it.combinations(b, 3):
u1 = list(u)
y =''.join(map(str, [1 if x%2 else 0 for x in u1]))
if y == combinations_3bit_without_repetition[i]:
c.append(u1)
good.append(c)
# output: [[[0, 2, 4]], [[0, 2, 3], [0, 2, 5], [0, 4, 5], [2, 4, 5]], [[0, 1, 2], [0, 1, 4], [0, 3, 4], [2, 3, 4]], [[0, 1, 3], [0, 1, 5], [0, 3, 5], [2, 3, 5]], [[1, 2, 3], [1, 2, 5], [1, 4, 5], [3, 4, 5]], [[1, 3, 5]]]
Can this be solved nicer and more economically?
Because the above solution seems to be "around" and for example the function it.combinations returns after each indexi from the list combinations_3bit_without_repetition all possible combinations, and only then the condition screens only the matching ones. In the case of large lists, this solution is weak;)
There is a much better way to generate the binary strings that you need:
import itertools
strings = ['{0:03b}'.format(i) for i in range(8)]
b = [0,1,2,3,4,5]
combinations = [list(x) for x in itertools.combinations(b, 3)]
dct = {}
for x in combinations:
y = ''.join(str(j%2) for j in x)
if y in dct:
dct[y].append(x)
else:
dct[y] = [x]
print(dct)
Output:
{'010': [[0, 1, 2], [0, 1, 4], [0, 3, 4], [2, 3, 4]], '011': [[0, 1, 3], [0, 1, 5], [0, 3, 5], [2, 3, 5]], '001': [[0, 2, 3], [0, 2, 5], [0, 4, 5], [2, 4, 5]], '000': [[0, 2, 4]], '101': [[1, 2, 3], [1, 2, 5], [1, 4, 5], [3, 4, 5]], '100': [[1, 2, 4]], '110': [[1, 3, 4]], '111': [[1, 3, 5]]}
Check to see if this does what you need. It creates a dictionary, where each key is a length 3 binary string, and each value is an array of combinations that match the binary string.
Here is an itertools.groupby solution using your b and your combinations_3bit_without_repetition:
def binarize(x):
return ''.join(map(str, map((1).__and__, x)))
srted = sorted(itertools.combinations(b, 3), key=binarize)
allowed = set(combinations_3bit_without_repetition)
result = [list(grp) for bn, grp in itertools.groupby(srted, binarize) if bn in allowed]
print(result)
Prints:
[[(0, 2, 4)], [(0, 2, 3), (0, 2, 5), (0, 4, 5), (2, 4, 5)], [(0, 1, 2), (0, 1, 4), (0, 3, 4), (2, 3, 4)], [(0, 1, 3), (0, 1, 5), (0, 3, 5), (2, 3, 5)], [(1, 2, 3), (1, 2, 5), (1, 4, 5), (3, 4, 5)], [(1, 3, 5)]]
Related
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]]
Here I wrote a recursive function to find the permutation of a list.
def backtrack(arr,tmp):
if len(tmp)==len(arr):
res.append(tmp)
#==print res here==
print(res)
else:
for i in range(len(arr)):
if arr[i] in tmp: continue
tmp.append(arr[i])
backtrack(arr,tmp)
tmp.pop()
if __name__ == '__main__':
points=[1,2,3]
res=[]
tmp=[]
backtrack(points,tmp)
print(res)
#code result
#[[1, 3, 2], [1, 3, 2]]
#[[2, 1, 3], [2, 1, 3], [2, 1, 3]]
#[[2, 3, 1], [2, 3, 1], [2, 3, 1], [2, 3, 1]]
#[[3, 1, 2], [3, 1, 2], [3, 1, 2], [3, 1, 2], [3, 1, 2]]
#[[3, 2, 1], [3, 2, 1], [3, 2, 1], [3, 2, 1], [3, 2, 1], [3, 2, 1]]
#[[], [], [], [], [], []]
I have no idea why the list 'res' defined in main() wont be updated when we pass it to a recursive function. Any suggestion about how to update 'res'?
When you do:
res.append(tmp)
you are appending to the global list res a reference to the list tmp. Any future changes to tmp will be visible through res as it just contains multiple references to the same tmp list.
Instead you probably want to append a copy of tmp:
res.append(list(tmp))
Make that change and your output is now:
[[1, 2, 3]]
[[1, 2, 3], [1, 3, 2]]
[[1, 2, 3], [1, 3, 2], [2, 1, 3]]
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1]]
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2]]
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
Alternatively you could convert the tmp list into a tuple:
res.append(tuple(tmp))
If you do that the option is then identical to the output returned by itertools.permutations:
>>> import itertools
>>> list(itertools.permutations([1,2,3]))
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
I want to perform the equivalent of the numpy
A[R][:,R]
but in pure python. As an example:
A = [[0, 1, 2], [1, 2, 3], [2, 3, 4]] and
R = [1, 2, 2]
the output should be:
[[2, 3, 3],[3, 4, 4], [3, 4, 4]]
Is there a nice way to do that in pure python?
I guess that would be [[A[i][k] for k in R] for i in R]
>>> A = [[0, 1, 2], [1, 2, 3], [2, 3, 4]] ; R = [1, 2, 2]
>>> np.array(A)[R][:,R]
array([[2, 3, 3],
[3, 4, 4],
[3, 4, 4]])
>>> [[A[i][k] for k in R] for i in R]
[[2, 3, 3], [3, 4, 4], [3, 4, 4]]
The closest built-in ability to numpy's "indexing with a list" is operator.itemgetter() with multiple parameters:
>>> import operator
>>> g = operator.itemgetter(*R)
>>> [g(row) for row in g(A)]
[(2, 3, 3), (3, 4, 4), (3, 4, 4)]
Having a list of lists,
mylist = [[1, 3, 4], [3, 6, 7], [8, 0, -1, 3]]
I need a method to get list containing indexes of all elements of some certain value, '3' for example. So for value of '3' such list of indexes should be
[[0, 1], [1, 0], [2, 3]]
Thanks in advance.
Update: we can have several instances of sought-for value ('3' in our case) in same sublist, like
my_list = [[1, 3, 4], [3, 6, 7], [8, 0, -1, 3, 3]]
So desired output will be [[0, 1], [1, 0], [2, 3], [2, 4]].
I suppose that my solution is slightly naive, here it is:
my_list = [[1, 3, 4], [3, 6, 7], [8, 0, -1, 3, 3]]
value = 3
list_of_indexes = []
for i in range(len(my_list)):
for j in range(len(my_list[i])):
if my_list[i][j] == value:
index = i, j
list_of_indexes.append(index)
print list_of_indexes
>>[(0, 1), (1, 0), (2, 3), (2, 4)]]
It will be great to see more compact solution
Assuming the value appears once in each sublist, you could use the following function, which makes use of the built in enumerate function and a list comprehension:
my_list = [[1, 3, 4], [3, 6, 7], [8, 0, -1, 3]]
def func(my_list, x):
return [[idx, sublist.index(x)] for idx, sublist in enumerate(my_list)]
answer = func(my_list, 3)
print(answer)
Output
[[0, 1], [1, 0], [2, 3]]
Easy way,
def get_val(mylist, val):
for ix, item in enumerate(mylist):
yield [ix, item.index(val)]
mylist = [[1, 3, 4], [3, 6, 7], [8, 0, -1, 3]]
val = list(get_val(mylist, 3))
print(val)
Output:
[[0, 1], [1, 0], [2, 3]]
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]]