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

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]

Related

Iterating sublists without using the list length

I have a list of things, and I need to apply some processing on successive (and overlapping) groups of 3 elements:
I can do it with:
for i in range(len(things)-2):
process(things[i:i+3])
So for instance:
things=[0, 1, 2, 3, 4, 5, 6, 7]
And I want to process:
[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7]
But is there a clever (but readable) way to do it without explicitly using len(things)?
Yes, what you're looking for is called a sliding/moving window. There are different ways to achieve this but the easiest is to use tee() and islice() functions from itertools. Using this you can define a window() function like below with default window size of 2.
import itertools
def window(iterable, n=2):
iters = itertools.tee(iterable, n)
for i, it in enumerate(iters):
next(itertools.islice(it, i, i), None)
return zip(*iters)
Then you can use it as
>>> things=[0, 1, 2, 3, 4, 5, 6, 7]
>>> list(window(things, n = 3))
[(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6, 7)]
>>> for elem in window(things, n = 3):
... print(elem)
...
(0, 1, 2)
(1, 2, 3)
(2, 3, 4)
(3, 4, 5)
(4, 5, 6)
(5, 6, 7)
Edit: For one time use a more simpler option may be
>>> list(zip(things, things[1:], things[2:]))
[(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6, 7)]
Another way of doing it could be:
for i in things[0:-2]:
a=things.index(i)
process(things[a:a+3])
Let's try using enumerate, Here len(things[i : i+len_]) == len_ is to drop uneven sized list that get's accumulated at the end iterations.
len_ = 3
[things[i : i+len_] for i, j in enumerate(things) if len(things[i : i+len_]) == len_]
[[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6], [5, 6, 7]]
len_ = 4
[things[i : i+len_] for i, j in enumerate(things) if len(things[i : i+len_]) == len_]
[[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7]]

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..

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

How to make a list of tuples from several lists?

I have 3 lists:
a = [0, 1, 2]
b = [3, 4, 5]
c = [6, 7, 8]
And I need to create a list of tuples from them.
The output should look like this:
[(0, 3, 6), (1, 4, 7), (2, 5, 8)]
Just using zip only.
a = [0, 1, 2]
b = [3, 4, 5]
c = [6, 7, 8]
zipped = list(zip(a, b, c))
Try this,
>>> a,b,c =[0, 1, 2],[3, 4, 5],[6, 7, 8]
>>> [(i,j,k) for i,j,k in zip(a,b,c)]
[(0, 3, 6), (1, 4, 7), (2, 5, 8)]
You can do it like so:
list(zip(a, b, c))

How to print an array in the form of key-value pairs in python?

I have a collection of arrays such as
a = [array([0, 1, 2, 3, 4]) array([0, 1, 2, 3]) array([0, 1, 2, 3, 4])
array([0, 1, 2, 3, 4, 5, 6, 7, 8]) array([0, 2, 3, 4, 5, 8, 9])
Is there any way to show this result is the form of key-value pairs like
[[(0),(1,2,3,4)],[(1),(0,2,3)],[(2),(0,1,3,4)],[(3),(0,1,2,4,5,6,7,8)]
[(4),(0,2,3,5,8,9)]]
i will get increment by 1 in the key and that value will be not included in the values list
I tried like this, but not able to put it into the required form.
c = [id for id in b if id != i] for i, b in enumerate(a)]
List comprehension with enumerate is one way. Note the comma after each single-item key. This represents that the object type is a tuple of length 1.
from numpy import array
a = [array([0, 1, 2, 3, 4]), array([0, 1, 2, 3]), array([0, 1, 2, 3, 4]),
array([0, 1, 2, 3, 4, 5, 6, 7, 8]), array([0, 2, 3, 4, 5, 8, 9])]
res = [[(i,), tuple(j for j in arr if j != i)] for i, arr in enumerate(a)]
# [[(0,), (1, 2, 3, 4)],
# [(1,), (0, 2, 3)],
# [(2,), (0, 1, 3, 4)],
# [(3,), (0, 1, 2, 4, 5, 6, 7, 8)],
# [(4,), (0, 2, 3, 4, 8, 9)]]
Alternatively, you can create a dictionary:
res_dict = {i: tuple(j for j in arr if j != i) for i, arr in enumerate(a)}
# {0: (1, 2, 3, 4),
# 1: (0, 2, 3),
# 2: (0, 1, 3, 4),
# 3: (0, 1, 2, 4, 5, 6, 7, 8),
# 4: (0, 2, 3, 4, 8, 9)}
You can try numpy approach:
import numpy as np
a = [np.array([0, 1, 2, 3, 4]),np.array([0, 1, 2, 3]),np.array([0, 1, 2, 3, 4]),
np.array([0, 1, 2, 3, 4, 5, 6, 7, 8]), np.array([0, 2, 3, 4, 5, 8, 9])]
print([[(i,),tuple(np.delete(j,np.argwhere(j==i)))] for i,j in enumerate(a)])
output:
[[(0,), (1, 2, 3, 4)], [(1,), (0, 2, 3)], [(2,), (0, 1, 3, 4)], [(3,), (0, 1, 2, 4, 5, 6, 7, 8)], [(4,), (0, 2, 3, 5, 8, 9)]]

Categories

Resources