find the unique indices from list

Viewed 100

I've two list

a = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0]
b = [4,4]

and the list may be like this as well

a = [1, 1, 1, 4, 1, 0, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0]
b = [1,4]

and i need the index position in the list a for the value which is there in list b

My Expected output should( These are index position of the value)

output- 
 1. [0,1]
 
 2. [0,3] 

This code is giving all index value where it matches

c_set = set() 
res = [] 
for idx, val in enumerate(test_list): 
    if val not in oc_set: 
        oc_set.add(val)          
    else: 
        res.append(idx) 

but i need the lenght of index value as list b, as i mentioned in my expected output.

Thanks in Advance

5 Answers

I don't see much hope in using index() here because your first example will give [0, 0] since it always returns the index of the first instance (if it exists). Instead, we can move through a and progressively slice the list to be searched. For each new slice, we increment an offset so we know how much of the list we lose each time a target is found.

We can also do a single conversion of the list to be searched into a set, for an O(1) check whether the item to be searched actually exists in the list.

def find(search, targets):
    
    peek = set(search)
    
    res = []
    offset = 0
    for target in targets:
        if target not in peek:
            res.append(None)
            continue
            
        for i, value in enumerate(search):
            if value == target:
                res.append(i + offset)
                offset += i + 1
                search = search[offset:]
                break
    return res

a = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0]
b = [4,4]
print(find(a, b))

a = [1, 1, 1, 4, 1, 0, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0]
b = [1,4]

print(find(a, b))

a = [1, 1, 1, 4, 1, 0, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0]
b = [1, 9, 4]

print(find(a, b))

A bit out there but works:

results = [None]*len(b)
for a_index, a_elem in enumerate(a):
    for b_index, b_elem in enumerate(b):
        if a_elem==b_elem and results[b_index]==None:
            results[b_index] = a_index
            a_elem = str(a_elem)
results

Gives the following outputs:

  1. [0,1]

  2. [0,3]

It even works if you need to find out the last matching index instead of first, with a minor amendment:

results = [None]*len(b)
for a_index, a_elem in enumerate(a):
    for b_index, b_elem in enumerate(b):
        if a_elem==b_elem :#and results[b_index]==None:
            results[b_index] = a_index
            a_elem = str(a_elem)
results

Does this work? The try cover the case where a value in b is not in a, which would add a None to the output

indices = []
for val in b:
    try:
        idx = a.index(val)
        indices.append(idx)
        a[idx] = None
    except:
        indices.append(None)

Outputs: [0, 1] and [0, 3]

EDIT: @Chris pointed out that using None is a better approach

From my comprehension of the problem:

a = [1, 1, 1, 4, 1, 0, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0]
b = [9,4]

[a.index(x) if x in a else None for x in b]

Output:

[None, 3]

I think this approach is more simple than others. Not sure about its performance though.

a = [1, 1, 1, 4, 1, 0, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0]
b = [1,4]
resp = []


def find_from_a(idx):
    for i, v in enumerate(a, start=idx):
        yield i, v


last_idx = 0
for lookup_val in b:
    for found_idx, found_val in find_from_a(idx=last_idx):
        if found_val == lookup_val:
            resp.append(found_idx)
            last_idx = found_idx
            break

print(resp)

If you always need to start from the beginning, just remove the last_idx variable and make it always start from the beginning.

Related