Home > Software design >  Making lists containing the positions of identical elements of two lists
Making lists containing the positions of identical elements of two lists

Time:08-19

Say two lists, X and Y are given in Python. Y contains X, but the elements in X may occur multiple times in Y and Y may contain other elements as well. I want to make lists that contain the positions of the elements in X in Y (each element apart). here is an example:

given X= [1, 8, 5, 6] and Y= [10, 5, 1, 8, 1, 8, 5, 1, 8, 6]

output :

  • [2, 4, 7] for "1"
  • [3, 5, 8] for "8"
  • [1, 6] for "5"
  • [9] for "6"

Here is my attempt:

x = 0
    Positions_x = []
    while x <= len(X):
        for pos, char in enumerate(Y):
            if char == X[x]:
                Positions_x.append(pos)
        x  = 1
        print(Positions_x)

And here is what i get as output:

[2, 4, 7]

[2, 4, 7, 3, 5, 8]

[2, 4, 7, 3, 5, 8, 1, 6]

[2, 4, 7, 3, 5, 8, 1, 6, 9]

Can anyone help me get the desired output?

CodePudding user response:

I would first construct a dict that stores positions of elements in Y, and then retrieve what are needed (based on X). In this way, you just need two un-nested loops.

from collections import defaultdict

X = [1, 8, 5, 6]
Y = [10, 5, 1, 8, 1, 8, 5, 1, 8, 6]

positions = defaultdict(list)

for i, y in enumerate(Y):
    positions[y].append(i)

output = {x: positions[x] for x in X}

print(output) # {1: [2, 4, 7], 8: [3, 5, 8], 5: [1, 6], 6: [9]}

CodePudding user response:

In your attempt, you do not empty positions list in each while loop. That why you print all numbers (indeces) you appended to the list

x = 0
    while x <= len(X):
        Positions_x = []
        for pos, char in enumerate(Y):
            if char == X[x]:
                Positions_x.append(pos)
        x  = 1
        print(Positions_x)

CodePudding user response:

A simple list comprehension seems the best way to solve this.

>>> x = [1, 8, 5, 6]
>>> y = [10, 5, 1, 8, 1, 8, 5, 1, 8, 6]
>>> [[i for i, v2 in enumerate(y) if v == v2] for v in x]
[[2, 4, 7], [3, 5, 8], [1, 6], [9]]

Or you might want a dictionary comprehension to know which set of indices go with which number.

>>> {v: [i for i, v2 in enumerate(y) if v == v2] for v in x}
{1: [2, 4, 7], 8: [3, 5, 8], 5: [1, 6], 6: [9]}

CodePudding user response:

Assuming you want your output to be a list of lists:

    x = 0
    Positions_x = []
    while x < len(X):
        positions = []
        for pos, char in enumerate(Y):
            if char == X[x]:
                positions.append(pos)
        Positions_x.append(positions)
        x  = 1
    print(Positions_x) 

Would get the following output:

[[2, 4, 7], [3, 5, 8], [1, 6], [9]]

CodePudding user response:

It seems that what you want is a function to which you can pass the elements of X and get a list with the indices of the occurrences of the element in Y. If that's what you want to do, you can do that with list comprehension like this:

X = [1, 8, 5, 6]
Y = [10, 5, 1, 8, 1, 8, 5, 1, 8, 6]

def get_indices(value, list):
    return [i for i, v in enumerate(list) if v == value]

Then simply pass the desired value from X together with Y as arguments to this function.

CodePudding user response:

Your original solution is almost there; you just need to create and print a new list for each value in X.

X = [1, 8, 5, 6]
Y = [10, 5, 1, 8, 1, 8, 5, 1, 8, 6]
for x in X:
    print([i for i, y in enumerate(Y) if y == x])

prints:

[2, 4, 7]
[3, 5, 8]
[1, 6]
[9]

CodePudding user response:

Simply get the indices in one (double) list comprehension:

ind = [[j for j, yj in enumerate(y) if yj == xi] for xi in x]

>>> ind
[[2, 4, 7], [3, 5, 8], [1, 6], [9]]

Then print them in the exact format desired:

>>> for i, jlist in enumerate(ind):
...     print(f'{jlist} for "{i}"')
[2, 4, 7] for "0"
[3, 5, 8] for "1"
[1, 6] for "2"
[9] for "3"

Optional, for speed

If you have long lists and speed is an issue (and of course you are no longer interested in printing the result, just getting the indices), then you could look into using numpy:

import numpy as np


o = np.argwhere(y == np.array(x)[:, None])
ind = [
    e.tolist()
    for e in np.split(o[:,1], np.unique(o[:, 0], return_index=True)[1][1:])
]

The array o contains the result as [[i, j], ...], where i is the "destination" index in our result, and j is the index in y. Thus, to convert that to the list of lists that we want, we do a "groupby" on the first column, as inspired by this.

CodePudding user response:

X = [1, 8, 5, 6] 
Y = [10, 5, 1, 8, 1, 8, 5, 1, 8, 6]

results = {}
for j in range(len(X)):
    indices = [i for i, x in enumerate(Y) if x == X[j]]
    results[X[j]] = indices

print(results)

Output:

{1: [2, 4, 7], 
8: [3, 5, 8], 
5: [1, 6], 
6: [9]}

Or you could ignore adding them to the results dictionary and use indices

CodePudding user response:

from typing import List


def find_positions(my_value: int, list_of_values: List[int]) -> List[int]:
    positions = []
    for i, v in enumerate(list_of_values):
        if v == my_value:
            positions.append(i)
    return positions


X = [1, 8, 5, 6]
Y = [10, 5, 1, 8, 1, 8, 5, 1, 8, 6]

result_as_list = [find_positions(x, Y) for x in X]
result_as_dict = {x: find_positions(x, Y) for x in X}


print(result_as_list) # [[2, 4, 7], [3, 5, 8], [1, 6], [9]]
print(result_as_dict) # {1: [2, 4, 7], 8: [3, 5, 8], 5: [1, 6], 6: [9]}

CodePudding user response:

positions = {}
test_list = [10, 5, 1, 8, 1, 8, 5, 1, 8, 6]
index_list = [5, 1, 8]

for index, value in enumerate(test_list):
    if value in positions:
        positions[value].append(index)
    else:
        positions[value] = [index]

for i in index_list:
    print(positions[i])
  • Related