0

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?

Star
  • 11
  • 2
  • 1
    Why do you add more positions to the same result list you just used for the previous input number and still contains those positions? – mkrieger1 Aug 18 '22 at 15:37

8 Answers8

2

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]}
Chris
  • 26,361
  • 5
  • 21
  • 42
  • I agree. I didnt know if @Star wanted is to understand what's making his output wrong or a better solution. – inarighas Aug 19 '22 at 07:52
1

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]}
j1-lee
  • 13,764
  • 3
  • 14
  • 26
0

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

Adam C
  • 71
  • 1
  • 6
0

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.

Schnitte
  • 1,193
  • 4
  • 16
0

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]
Samwise
  • 68,105
  • 3
  • 30
  • 44
0

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.

Pierre D
  • 24,012
  • 7
  • 60
  • 96
-1
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]}

cestlarumba
  • 198
  • 6
-2
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])
Pioneer_11
  • 670
  • 4
  • 19