-1

I want to check if the input number is in the list, and if so - add its index in the original list to the new one. If it's not in the list - I want to add a -1.

I tried using the for loop and adding it like that, but it is kind of bad on the speed of the program.

n = int(input())
k = [int(x) for x in input().split()]
z = []
m = int(input())
for i in range(m):
    a = int(input())
    if a in k: z.append(k.index(a))
    else: z.append(-1)

The input should look like this :

3
2 1 3
1
8
3

And the output should be :

1
-1
2

How can I do what I'm trying to do more efficiently/quickly

  • 1
    Yes, but why not use `.find` instead? You should also note that appending to the list may not be the bottleneck, a dictionary mapping value to index may speed this up more substantially. – jonrsharpe Apr 24 '21 at 15:49
  • 2
    Just a general note about list comprehension. List comprehension is just [syntactic sugar](https://en.wikipedia.org/wiki/Syntactic_sugar) for `for` loops. They are minimally more efficient at building a list (See: [Are list-comprehensions and functional functions faster than “for loops”?](https://stackoverflow.com/q/22108488/15497888)). Your question probably should be something like: "How can I do what I'm trying to do more efficiently/quickly?". – Henry Ecker Apr 24 '21 at 15:50
  • 1
    I agree with @HenryEcker , it depends also on the usage, if you have a large list you can also implement one of [this search algorithms](https://www.techwalla.com/articles/types-of-search-algorithms) or even use [threads](https://docs.python.org/3/library/threading.html) to do the job. – emichester Apr 24 '21 at 15:56
  • 1
    By the way, we're all asuming that there is only one ocurrence of any value in the list to find in, because the `list.index()`will stop searching once it has found the first ocurrence (see [docs](https://docs.python.org/3/tutorial/datastructures.html) and [extra docs](https://www.w3schools.com/python/ref_list_index.asp)) – emichester Apr 24 '21 at 16:22

2 Answers2

0

Adapt this solution for your problem.

def test(list1,value):
    try:
        return list1.index(value)
    except ValueError as e:
        print(e)
        return -1

list1=[2, 1, 3]
in1 = [1,8,3]
res= [test(list1,i) for i in in1]
print(res)
  • output
8 is not in list
[1, -1, 2]
DevScheffer
  • 491
  • 4
  • 15
  • In your `test()`methos you better use just this `return list1.index(value) if value in list1 else -1` because you shouldn't be handling Exceptions all the time that value is not in list. – emichester Apr 24 '21 at 16:19
  • Add `KeyValue` to the `except` for good style. – Joffan Apr 24 '21 at 19:00
0

There are many approaches to this problem. This is typical when you're first starting in programming as, the simpler the problem, the more options you have. Choosing which option depends what you have and what you want.

In this case we're expecting user input of this form:

3
2 1 3
1
8
3

One approach is to generate a dict to use for lookups instead of using list operations. Lookup in dict will give you better performance overall. You can use enumerate to give me both the index i and the value x from the list from user input. Then use int(x) as the key and associate it to the index.

The key should always be the data you have, and the value should always be the data you want. (We have a value, we want the index)

n = int(input())

k = {}
for i, x in enumerate(input().split()):
    k[int(x)] = i

z = []
for i in range(n):
    a = int(input())
    if a in k:
        z.append(k[a])
    else:
        z.append(-1)

print(z)

k looks like:

{2: 0, 1: 1, 3: 2}

This way you can call k[3] and it will give you 2 in O(1) or constant time.

(See. Python: List vs Dict for look up table)


There is a structure known as defaultdict which allows you to specify behaviour when a key is not present in the dictionary. This is particularly helpful in this case, as we can just request from the defaultdict and it will return the desired value either way.

from collections import defaultdict

n = int(input())

k = defaultdict(lambda: -1)
for i, x in enumerate(input().split()):
    k[int(x)] = i

z = []
for i in range(n):
    a = int(input())
    z.append(k[a])

print(z)

While this does not speed up your program, it does make your second for loop easier to read. It also makes it easier to move into the comprehension in the next section.

(See. How does collections.defaultdict work?


With these things in place, we can use, yes, list comprehension, to very minimally speed up the construction of z and k. (See. Are list-comprehensions and functional functions faster than “for loops”?

from collections import defaultdict

n = int(input())

k = defaultdict(lambda: -1)
for i, x in enumerate(input().split()):
    k[int(x)] = i

z = [k[int(input())] for i in range(n)]

print(z)

All code snippets print z as a list:

[1, -1, 2]

See Printing list elements on separated lines in Python if you'd like different print outs.


Note: The index function will find the index of the first occurrence of the value in a list. Because of the way the dict is built, the index of the last occurrence will be stored in k. If you need to mimic index exactly you should ensure that a later index does not overwrite a previous one.

for i, x in enumerate(input().split()):
    x = int(x)
    if x not in k:
        k[x] = i
Henry Ecker
  • 34,399
  • 18
  • 41
  • 57