Check for reverse pair repetition in two arrays in python - 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..

Related

How can I find matching elements and indices from two arrays?

For example,
a = [1, 1, 2, 4, 4, 4, 5, 6, 7, 100]
b = [1, 2, 2, 2, 2, 4, 5, 7, 8, 100]
I can find the matching elements using:
np.intersect1d(a,b)
Output:
array([ 1, 2, 4, 5, 7, 100])
Then, how can I get the indices of matched elements in arrays a and b, respectively ?
There is a function in IDL as "match" - https://www.l3harrisgeospatial.com/docs/match.html
Is there a similar function in Python?
Use return_indices in numpy.intersect1d:
intersect, ind_a, ind_b = np.intersect1d(a,b, return_indices=True)
Output:
intersect
# array([ 1, 2, 4, 5, 7, 100])
ind_a
# array([0, 2, 3, 6, 8, 9], dtype=int64)
ind_b
# array([0, 1, 5, 6, 7, 9], dtype=int64)
Which can then be reused like:
np.array(a)[ind_a]
np.array(b)[ind_b]
array([ 1, 2, 4, 5, 7, 100])
you can track indexes using enumerate as follows:
a = [1, 1, 2, 4, 4, 4, 5, 6, 7, 100]
b = [1, 2, 2, 2, 2, 4, 5, 7, 8, 100]
# 0 1 2 3 4 5 6 7 8 9
print([i for i,x in enumerate(zip(a,b)) if x[0] == x[1]])
[0, 2, 5, 6, 9]
so what's going on here?!
We're taking advantage of the amazing enumerate function! This function generates a tuple for each element in an iterable, with the first element being the enumeration (or the index in this case) and the second being the iterable.
Heres what the enumeration of zip(a,b) looks like
[(0, (1, 1)), (1, (1, 2)), (2, (2, 2)), (3, (4, 2)), (4, (4, 2)), (5, (4, 4)), (6, (5, 5)), (7, (6, 7)), (8, (7, 8)), (9, (100, 100))]
# lets look a little closer at one element
(0, (1, 1))
# ^ ^
# index iterable
From there on it's simple! Unpack the iterable and check if both elements are equal, and if they are then use append the enumeration # to a list!
Use range like so:
matching_idxs = [idx for idx in range(len(a)) if a[idx] == b[idx]]
print(matching_idxs)
# [0, 2, 5, 6, 9]
Using enumerate and zip:
a = [1, 1, 2, 4, 4, 4, 5, 6, 7, 100]
b = [1, 2, 2, 2, 2, 4, 5, 7, 8, 100]
output = [(i, x) for i, (x, y) in enumerate(zip(a, b)) if x == y]
print(output)
[(0, 1), (2, 2), (5, 4), (6, 5), (9, 100)]
This results in a list of tuples being (index, value)
this is very straightforward with the help of zip function to loop two lists in parallel:
>>> count = 0
>>> indices = []
>>> for x, y in zip(a, b):
if x == y:
indices.append(count)
count += 1
>>> indices
[0, 2, 5, 6, 9]

Listing all combination of list 1 to n given length restriction k

I found a code that recursively returns all combination of a list of 1 to n numbers with length k
def choose_iter(elements, length):
for i in range(len(elements)):
if length == 1:
yield (elements[i],)
else:
for next in choose_iter(elements[i+1:len(elements)], length-1):
yield (elements[i],) + next
def choose(l, k):
return list(choose_iter(l, k))
this will return what I need but can I modify this so that I dont have to use the yield function? I haven't studied yield yet and I don't want to confuse myself with this.
You can do it using itertools:
import itertools
for combination in itertools.combinations([i for i in range(1, n+1)], k):
print(combination)
For n=7 and k=5, you have:
(1, 2, 3, 4, 5)
(1, 2, 3, 4, 6)
(1, 2, 3, 4, 7)
(1, 2, 3, 5, 6)
(1, 2, 3, 5, 7)
(1, 2, 3, 6, 7)
(1, 2, 4, 5, 6)
(1, 2, 4, 5, 7)
(1, 2, 4, 6, 7)
(1, 2, 5, 6, 7)
(1, 3, 4, 5, 6)
(1, 3, 4, 5, 7)
(1, 3, 4, 6, 7)
(1, 3, 5, 6, 7)
(1, 4, 5, 6, 7)
(2, 3, 4, 5, 6)
(2, 3, 4, 5, 7)
(2, 3, 4, 6, 7)
(2, 3, 5, 6, 7)
(2, 4, 5, 6, 7)
(3, 4, 5, 6, 7)
I think this should be the correct code
def choose_iter(elements, length):
for i in range(len(elements)):
if length == 1:
yield (elements[i],)
else:
for j in choose_iter(elements[:len(elements)], length - 1):
yield (elements[i],) + j
def choose(l, k):
for i in choose_iter(l, k):
print(i)
yield is similar to return but in this case, you need the yield statement otherwise the code will not work. You can check
What does the "yield" keyword do?
for more info.
And also avoid using "next" as a variable because it's also a python function.
Hope I helped.

Permutations Function Issue

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)]

How to insert elements from one list to another generating all possible combinations

Hello guys I need some help with lists in python. Suppose I have two lists.
a = [3,1,5]
b = [2,4]
What I want is to insert the elements of the list b consecutively (without changing the order of a) generating new lists. For example.
ans = [[2,4,3,1,5],[2,3,4,1,5],[2,3,1,4,5],[2,3,1,5,4],[3,2,4,1,5]...]
Thaks for your help I hope I was able to express myself correctly.
Not the most clean way of doing this, but here's what I mean:
from itertools import permutations
a = [3,1,5]
b = [2,4]
def a_order_is_same(perm):
i3, i1, i5 = perm.index(3), perm.index(1), perm.index(5)
return i3 < i1 < i5
ans = [p for p in permutations(a+b) if a_order_is_same(p)]
for p in ans:
print(p)
--------------------------------------------------
(3, 1, 5, 2, 4)
(3, 1, 5, 4, 2)
(3, 1, 2, 5, 4)
(3, 1, 2, 4, 5)
(3, 1, 4, 5, 2)
(3, 1, 4, 2, 5)
(3, 2, 1, 5, 4)
(3, 2, 1, 4, 5)
(3, 2, 4, 1, 5)
(3, 4, 1, 5, 2)
(3, 4, 1, 2, 5)
(3, 4, 2, 1, 5)
(2, 3, 1, 5, 4)
(2, 3, 1, 4, 5)
(2, 3, 4, 1, 5)
(2, 4, 3, 1, 5)
(4, 3, 1, 5, 2)
(4, 3, 1, 2, 5)
(4, 3, 2, 1, 5)
(4, 2, 3, 1, 5)
I give you another option.
import itertools
a = [3,1,5]
b = [2,4]
c = [b +[a]][0] #0 to get only one level of nested
perm = [x for x in itertools.permutations(c, 3)]
ans = []
Here is the formula to get your "ans" output:
for i in range(len(perm)):
groups = perm[i] #this is the subset like [2, 4, [3, 1, 5]]
#flatten the list or returns integer
clean = [y for x in groups for y in (x if isinstance(x,list) else [x])]
ans.append(clean)
print(clean)
[[2, 4, 3, 1, 5], [2, 3, 1, 5, 4], [4, 2, 3, 1, 5], [4, 3, 1, 5, 2], [3, 1, 5, 2, 4], [3, 1, 5, 4, 2]]

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

Categories

Resources