Permutations Function Issue - python

I've been struggling with defining a function that returns the permutations of a given array.
I have written the code below:
def gPermutations(array):
result = []
idx = 0
for element in array:
for i in range(len(array)):
if i != idx:
z = array[:array.index(element)]
z.append(array[i])
s = z[:] + array[array.index(element)+1:]
s[i] = element
result.append(s)
idx += 1
return result
This code seems to work by returning some of the permutations of an array, but doesn't return all of them, and sometimes duplicates a certain permutation. May someone please explain what is the issue with my code? Thanks!

Use the permutations method from itertools
In [1]: from itertools import permutations
In [2]: arr = [1,2,3,4]
In [3]: for perm in permutations(arr, len(arr)):
...: print(perm)
...:
(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)

If you truly want all the permutations (re-orderings?) of your list, I'd use the itertools package:
>>> from itertools import permutations
>>> array = [1, 2, 3]
>>> print(list(permutations(array)))
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]

Related

To generate a list, allowing duplicates and fitting a condition

From choices [1,2,3], I want to output all possible combinations, allowing duplicates in the choices, in a list of 5 elements.
In each of the lists, there must be at least one of 1, at least one of 2, and at least one of 3.
A clumsy way as below. It firstly generates a list of 5 using either in [1,2,3]. All generated lists are examined to have at least each of [1,2,3]. The qualified ones are put into a big list. Then the duplicates in the big list are removed (loop it many times to make sure good coverage):
import random
import itertools
choices = [1,2,3]
big_list = []
for a in range(10000):
new_list = [random.choice(choices) for i in range(5)]
if new_list.count(1) >= 1 and new_list.count(2) >= 1 and new_list.count(3) >= 1:
big_list.append(new_list)
big_list.sort()
final_list = list(big_list for big_list, _ in itertools.groupby(big_list))
# this line to remove the duplicates in the list of lists
print (final_list)
Considering the sequence matters, that is, [1,1,1,2,3] and [2,3,1,1,1] are two different lists.
What would be the smarter and more comprehensive way to do so?
Maybe you could could use itertools.combinations_with_replacement, itertools.permutations along with collections.Counter:
>>> from collections import Counter
>>> from itertools import combinations_with_replacement, permutations
>>>
>>> def is_valid_combination(comb: tuple) -> bool:
... digit_counts = Counter(comb)
... return digit_counts[1] >= 1 and \
... digit_counts[2] >= 1 and \
... digit_counts[3] >= 1
...
>>> choices = [1, 2, 3]
>>> valid_combinations = [
... c for c in combinations_with_replacement(choices, r=5)
... if is_valid_combination(c)
... ]
>>>
>>> valid_combinations
[(1, 1, 1, 2, 3), (1, 1, 2, 2, 3), (1, 1, 2, 3, 3), (1, 2, 2, 2, 3), (1, 2, 2, 3, 3), (1, 2, 3, 3, 3)]
>>>
>>> all_permutations_of_valid_combinations = {
... p
... for c in valid_combinations for p in permutations(c)
... }
>>>
>>> all_permutations_of_valid_combinations
{(2, 1, 3, 1, 2), (2, 1, 3, 2, 1), (3, 3, 2, 1, 3), (1, 2, 3, 2, 3), (1, 2, 1, 3, 1), (3, 1, 2, 3, 2), (3, 3, 3, 2, 1), (3, 2, 2, 1, 1), (1, 2, 2, 3, 1), (1, 3, 2, 2, 3), (1, 3, 2, 3, 2), (1, 2, 1, 1, 3), (3, 1, 3, 3, 2), (3, 1, 1, 2, 3), (2, 1, 3, 2, 3), (1, 2, 2, 1, 3), (1, 2, 1, 3, 3), (2, 3, 3, 1, 2), (2, 3, 3, 2, 1), (3, 3, 1, 2, 1), (3, 2, 3, 2, 1), (1, 2, 2, 3, 3), (3, 2, 1, 1, 1), (2, 2, 1, 3, 1), (2, 3, 1, 1, 1), (1, 3, 1, 2, 3), (3, 3, 1, 1, 2), (3, 2, 3, 1, 2), (2, 1, 2, 3, 1), (2, 2, 1, 1, 3), (3, 2, 1, 3, 1), (2, 3, 1, 3, 1), (1, 1, 3, 2, 1), (2, 3, 2, 1, 2), (2, 3, 2, 2, 1), (2, 1, 2, 1, 3), (3, 2, 1, 1, 3), (2, 2, 1, 3, 3), (2, 3, 1, 1, 3), (2, 3, 1, 2, 2), (3, 2, 3, 3, 1), (1, 1, 3, 1, 2), (2, 1, 2, 3, 3), (3, 3, 2, 2, 1), (3, 1, 2, 1, 2), (3, 2, 1, 3, 3), (3, 1, 2, 2, 1), (2, 3, 1, 3, 3), (1, 1, 3, 2, 3), (3, 3, 3, 1, 2), (1, 2, 3, 1, 1), (1, 1, 3, 3, 2), (3, 1, 3, 1, 2), (2, 3, 2, 3, 1), (1, 3, 2, 1, 1), (2, 1, 3, 3, 1), (3, 2, 2, 3, 1), (3, 1, 2, 2, 3), (1, 3, 2, 2, 2), (1, 2, 3, 1, 3), (1, 3, 2, 3, 1), (3, 2, 2, 1, 3), (2, 2, 3, 2, 1), (3, 1, 1, 2, 2), (1, 1, 2, 2, 3), (2, 1, 3, 2, 2), (1, 3, 3, 2, 2), (3, 3, 1, 3, 2), (2, 1, 1, 3, 1), (1, 3, 2, 1, 3), (2, 1, 3, 3, 3), (3, 1, 3, 2, 2), (2, 2, 3, 1, 2), (1, 1, 2, 3, 1), (3, 2, 1, 2, 2), (1, 2, 2, 3, 2), (3, 3, 1, 2, 3), (1, 3, 2, 3, 3), (1, 2, 1, 2, 3), (3, 2, 3, 1, 1), (1, 3, 1, 2, 2), (1, 2, 2, 2, 3), (2, 1, 1, 3, 3), (3, 1, 1, 3, 2), (1, 1, 2, 3, 3), (1, 3, 3, 3, 2), (2, 3, 2, 1, 1), (2, 2, 1, 2, 3), (2, 2, 1, 3, 2), (1, 2, 3, 3, 1), (3, 2, 3, 1, 3), (2, 3, 1, 2, 1), (2, 1, 3, 1, 1), (3, 3, 2, 1, 2), (1, 2, 3, 2, 2), (1, 3, 1, 3, 2), (3, 1, 2, 3, 1), (2, 2, 2, 3, 1), (2, 1, 2, 2, 3), (1, 2, 3, 3, 3), (2, 3, 1, 2, 3), (2, 1, 3, 1, 3), (3, 2, 2, 2, 1), (1, 2, 1, 3, 2), (2, 3, 3, 1, 1), (3, 1, 2, 3, 3), (3, 2, 2, 1, 2), (3, 1, 1, 2, 1), (1, 3, 3, 2, 1), (2, 3, 3, 3, 1), (2, 1, 1, 1, 3), (1, 3, 2, 1, 2), (2, 1, 3, 3, 2), (1, 1, 1, 2, 3), (3, 1, 3, 2, 1), (1, 1, 1, 3, 2), (2, 2, 3, 1, 1), (3, 1, 1, 1, 2), (1, 1, 2, 1, 3), (1, 3, 3, 1, 2), (3, 2, 1, 2, 1), (2, 3, 3, 1, 3), (3, 3, 1, 2, 2), (2, 2, 3, 3, 1), (1, 3, 1, 2, 1), (1, 3, 3, 2, 3), (3, 2, 1, 1, 2), (2, 1, 1, 3, 2), (2, 3, 1, 1, 2), (3, 1, 3, 2, 3), (2, 2, 3, 1, 3), (1, 3, 1, 1, 2), (1, 1, 2, 3, 2), (2, 1, 2, 3, 2), (3, 2, 1, 2, 3), (3, 1, 2, 1, 1), (3, 2, 1, 3, 2), (2, 1, 1, 2, 3), (2, 3, 1, 3, 2), (1, 1, 3, 2, 2), (2, 3, 2, 1, 3), (3, 3, 2, 3, 1), (3, 3, 2, 1, 1), (1, 2, 3, 2, 1), (3, 1, 2, 1, 3), (2, 2, 2, 1, 3), (3, 1, 2, 2, 2), (1, 3, 2, 2, 1), (1, 2, 3, 1, 2), (1, 2, 3, 3, 2)}
Apart from the itertools.combinations itself, you could use some recursive logic:
def combinations(choices, n = 5):
if n == 1:
return [[x,] for x in choices]
else:
return [v + [x,] for v in combinations(choices, n = n -1) for x in choices]
To select only the combinations which contain at least one 1, 2 and 3:
[x for x in combinations(choices, n = 5) if all(c in x for c in choices)]

Check for reverse pair repetition in two arrays in python

I have two arrays as follows:
a = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5]
b = [1, 2, 5, 1, 3, 2, 3, 4, 3, 5, 1, 4]
All the possible pairs these two arrays can form are (a[0],b[0]),(a[1],b[1]),(a[2],b[2]),(a[3],b[3]),...,(a[11],b[11]). The two arrays have same length and a pair is formed between same indices.
The problem is to check that how many pairs are there who have a reverse pair present for them.
For example, in the arrays I provided above the pairs (a[1],b[1]) and (a[3],b[3]) form one reverse pair because (1,2) and (2,1) are reverse of each other. Similarly (a[2],b[2]) forms a reverse pair with (a[10],b[10]). Can someone guide me how to count the total number of reverse pairs that exist between two arrays?
Thanks a lot for your time.
A = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5]
B = [1, 2, 5, 1, 3, 2, 3, 4, 3, 5, 1, 4]
for pair in zip(A,B):
rpair = pair[::-1]
print(pair,rpair)
Result:
(1, 1) (1, 1)
(1, 2) (2, 1)
(1, 5) (5, 1)
(2, 1) (1, 2)
(2, 3) (3, 2)
(3, 2) (2, 3)
(3, 3) (3, 3)
(3, 4) (4, 3)
(4, 3) (3, 4)
(4, 5) (5, 4)
(5, 1) (1, 5)
(5, 4) (4, 5)
A = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5]
B = [1, 2, 5, 1, 3, 2, 3, 4, 3, 5, 1, 4]
for pair in zip(A,B):
rpair = pair[::-1]
if pair[0] == rpair[1] and pair[1] == rpair[0]:
print(pair,rev_pair)
Result
(1, 1) (4, 5)
(1, 2) (4, 5)
(1, 5) (4, 5)
(2, 1) (4, 5)
(2, 3) (4, 5)
(3, 2) (4, 5)
(3, 3) (4, 5)
(3, 4) (4, 5)
(4, 3) (4, 5)
(4, 5) (4, 5)
(5, 1) (4, 5)
(5, 4) (4, 5)
Final
A = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5]
B = [1, 2, 5, 1, 3, 2, 3, 4, 3, 5, 1, 4]
n = 0
for pair in zip(A,B):
rpair = pair[::-1]
if pair[0] == rpair[1] and pair[1] == rpair[0]:
n = n + 1
print('total pairs : {}'.format(n))
Result
total pairs : 12
This is a pretty vague question.
Do you want to count +1 if a single reverse pair is present, or +n if n reverse of (a[i], b[i]) is found in the arrays?
How about only counting reverse pairs a single time?
Should (1, 1) be counted as a reverse pair, or not?
For the future, perhaps show the answer you expect for your simple test-system.
I would expect that your test-system should give n=12 reverse pairs, assuming you only count reverse pair a single time in the calculation.
Just a simple implementation that is easy to read:
A = [1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5]
B = [1, 2, 5, 1, 3, 2, 3, 4, 3, 5, 1, 4]
n = 0
pairs = [pair for pair in zip(A, B)]
for rev_pair in zip(B, A):
if rev_pair in pairs:
n += 1
I'm sure a much faster implementation could be made..

Get all combination of list with repeated values

How can i get a list of all possible values of a list with also repeated ones?
I've tried itertools.combination_with_replacement and itertools.permutation but the first exclude the inverted order (such as [3, 2, 1]) and the second exclude multiple values (such as [3, 3, 1]).
I need something like this:
Example:
list = [1, 2, 3]
results =
[1, 1, 1]
[1, 1, 2]
[1, 1, 3]
...
[3, 1, 1]
[3, 1, 2]
[3, 1, 3]
...
What can I do in Python to achieve this?
Thanks in advance.
You're looking for itertools.product, setting the repetition to 3:
>>> from itertools import product
>>> lst = [1, 2, 3]
>>> list(product(lst, repeat=3))
[(1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 1), (1, 2, 2), (1, 2, 3), (1, 3, 1), (1, 3, 2), (1, 3, 3), (2, 1, 1), (2, 1, 2), (2, 1, 3), (2, 2, 1), (2, 2, 2), (2, 2, 3), (2, 3, 1), (2, 3, 2), (2, 3, 3), (3, 1, 1), (3, 1, 2), (3, 1, 3), (3, 2, 1), (3, 2, 2), (3, 2, 3), (3, 3, 1), (3, 3, 2), (3, 3, 3)]

get the count of elements of tuples of your own...not just the range or sequence

The below code is running for first three elements of the tuple of this list
SS1=[(1, 2, 3, 4, 5), (1, 2, 3, 4, 6), (1, 2, 3, 5, 6), (1, 2, 4, 5, 6), (1, 3, 4, 5, 6), (2, 3, 4, 5, 6)]
from collections import Counter
c = Counter(elem[0:3] for elem in SS1)
for k, v in c.items():
if (v > 0):
print(k,v)
and the output is:
(1, 2, 3) 3
(1, 2, 4) 1
(1, 3, 4) 1
(2, 3, 4) 1
But my expectation is not just for first three tuple...i want the counter for tuple (0,2,3) or tuple (1,2,4) likewise i can pass any three position of the tuple and get the count of it... How can I do this?
If what i understood from your question is correct, the code below will solve your issue:
SS1=[(1, 2, 3, 4, 5), (1, 2, 3, 4, 6), (1, 2, 3, 5, 6), (1, 2, 4, 5, 6), (1, 3, 4, 5, 6), (2, 3, 4, 5, 6)]
from collections import Counter
def get_new_list(a, pos):
# Check if any element in pos is > than the length of the tuples
if any(k >= len(min(SS1, key=lambda x: len(x))) for k in pos):
return
for k in a:
yield tuple(k[j] for j in pos)
def elm_counter(elm):
if not len(elm):
return
c = Counter(elm)
for k, v in c.items():
if v > 0:
print(k, v)
elm = list(get_new_list(SS1, (0, 2, 4)))
elm_counter(elm)
print('---')
elm = list(get_new_list(SS1, (1, 2, 4)))
elm_counter(elm)
Output:
(1, 3, 5) 1
(1, 3, 6) 2
(1, 4, 6) 2
(2, 4, 6) 1
---
(2, 3, 6) 2
(2, 3, 5) 1
(3, 4, 6) 2
(2, 4, 6) 1

Creating an array with unique rows and columns

How do I create an array with unique rows and columns like this one in python?
[1, 2, 3, 4]
[2, 3, 4, 1]
[4, 1, 2, 3]
[3, 4, 1, 2]
from itertools import permutations
from random import choice
>>> a = list(permutations([1,2,3,4], 4))
>>> total = [choice(a) for i in range(4)]
>>> total
[(3, 4, 1, 2), (4, 1, 2, 3), (2, 1, 4, 3), (1, 2, 3, 4)]
>>> print(*(' '.join(map(str, item)) for item in total), sep='\n')
3 4 1 2
4 1 2 3
2 1 4 3
1 2 3 4
This can be easily achieved with the itertools.permutations method:
import itertools
a = [1,2,3,4]
list(itertools.permutations(a))
[(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)]

Categories

Resources