6

I have this

s = ['son','abc','pro','bro']
b = ['son','bro']
c = ['pro','quo']

The expected output is this. Where items in the output are index(item_in_s) if it is present in list b. Or index(item_in_s)+10 if an item is in c.

[0,12,3]

I tried this:

index_list = [s.index(item) if item in b else s.index(item)+10 if item in c for item in s]
print(index)

But apparently this is a syntax error. So I tried this:

index_list = [s.index(item) if item in b else s.index(item)+10 for item in s if item in c]
    print(index)

Output:

[12]

This just changes the whole logic. Although I could do this

fin = [s.index(item) if item in b else s.index(item)+10 if item in c  else '' for item in s]
fin = [item for item in fin if item!='']
print(fin)

Desired output obtained:

[0, 12, 3]

But how do I obtain what I want in list comprehension itself or is there something like else continue in list comprehensions?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
void
  • 2,571
  • 2
  • 20
  • 35
  • I don't really understand what you're trying to do here. – Sam Jun 13 '17 at 06:15
  • simply put something like `[x if x in list1 else x+10 if x in list2 for x in my_list]` which gives a syntax error. – void Jun 13 '17 at 06:17
  • I want something like `[x if x in list1 else x+10 if x in list2 else pass for x in my_list]` but i know pass gives syntax error too. Any alternatives? – void Jun 13 '17 at 06:18
  • Split your code into several lines. I don't understand what kind of output you are after in relation to the input – Sam Jun 13 '17 at 06:20
  • 1
    Just. Write. A. For. Loop. And use `enumerate` instead of `.index` which makes your algorithm inefficient. – juanpa.arrivillaga Jun 13 '17 at 06:20
  • Oh thanks for the tip first i used enumerate i thought that would be inefficient. You are right it would search everytime yes. – void Jun 13 '17 at 06:22

4 Answers4

11

Fundamentally, a list-comprehension forces you to be very inefficient:

>>> [i if item in b else i + 10 if item in c else None for i, item in enumerate(s) if item in b or item in c]
[0, 12, 3]

This has to check the membership item in b and c twice each in the worst-case if you want that output. Instead, just use a for-loop:

>>> index_list = []
>>> for i, item in enumerate(s):
...     if item in b:
...         index_list.append(i)
...     elif item in c:
...         index_list.append(i + 10)
...     else item in c:
...         index_list.append(None)
...
>>> index_list
[0, 12, 3]
>>>

Simple, readable, straight-forward and Pythonic.

Edit

You can do something close to this with assignment expressions:

[
    i if item_in_b else i + 10 if item_in_c else None 
    for i, item in enumerate(s) 
    if (item_in_b:=item in b) or (item_in_c:=item in c)
]

but I still prefer the loop.

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
  • The condition `item in b` could be removed and only checked once when Python 3.8 comes and we can use `(item_in_b := item in b)` and do `if item_in_b` later on. – GeeTransit Jun 26 '19 at 19:38
1
index_list = [s.index(item) if item in b else s.index(item) + 10 for item in s if item in b or item in c]

We make sure it's in either b or c, and then the index will be either of the cases.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
codelessbugging
  • 2,849
  • 1
  • 14
  • 19
1

your solution glitch can be solved by avoiding the elements that doesn't exist in list b&c.

you can do this by creating new list and applying simple set operation

check this little change in your solution.

fin = [s.index(item) if item in b else s.index(item)+10 if item in c  else '' for item in list(set(b+c)&set(s))]

by doing this your conditinal statement else is never going to execute cause list on which you are iterating only has element that either list in b or c only.

Community
  • 1
  • 1
DexJ
  • 1,264
  • 13
  • 24
1

already good answers given, here is one which is not mentioned yet:

fin = [item for item in ([s.index(item) if item in b else s.index(item)+10 if item in c  else '' for item in s]) if item!='']
print(fin)

basically it is a combination of the original 2 lines of code:

fin = [s.index(item) if item in b else s.index(item)+10 if item in c  else '' for item in s]
fin = [item for item in fin if item!='']

Not necessarily "faster or better", just a combination which was not given before. When doing list comprehensions you always have the risk that you iterate more than you really need to.

A better solution would be a for loop, which is given in another answer.

SiHa
  • 7,830
  • 13
  • 34
  • 43
Edwin van Mierlo
  • 2,398
  • 1
  • 10
  • 19
  • It would be more useful if you could explain how your solution works, and how it is better than the other answers. Code-only answers are not terribly helpful. – SiHa Jun 13 '17 at 07:01