# remove elements in one list according to the conditions on corresponding elements of another list

I have two lists that have the same length, lstA, lstB, I want to remove elements that are not good based on some conditions, but at the meantime, I also want to remove the elements in lstB that have the same position with the unwanted one in lstA. like below:

lstA = ['good','good2', '']
lstB = [1,2,3]


I want '' in lstA and 3 in lstB removed:

results:
lstA = ['good','good2']
lstB = [1,2]


Currently, I am doing this:

lstB = [lstB[i] for i in range(len(lstB)) if lstA[i] != '']
lstA = [st for st in lstA if st != '']


Want a more elegant and pythonic way of doing this

Rather than two comprehensions, it'd be simpler to just use one for loop. Make new_list_a and new_list_b start empty, and if the item is good add to both at the same time. This is simpler to understand, as you see clearly that both are being filtered by the same thing.

new_list_a = []
new_list_b = []
for a, b in zip(list_a, list_b):
if a != '':
new_list_a.append(a)
new_list_b.append(b)


However, it looks like you'd be better served if you only create one list. This means you can have a tuple of (a, b). And so could implement something like:

[(a, b) for a, b in zip(list_a, list_b) if a != '']

• Yes, indeed, actually I am doing my data cleaning, so, the two lists are interconnected since they are data and labels. And by making them a tuple, I am indeed better served! Thank you! – YoarkYANG Nov 2 '17 at 9:34
• You could also use filter instead of a list comprehension. I don't know - and would be interested to know - which one is considered better, more pythonic, and why. – Nico Nov 2 '17 at 13:21
• @Nico I generally don't use filter, map or reduce. Guido van van Rossum has previously wanted to remove them, and comprehensions are generally superior. Also Google's style guide recommends against them, where PEP 8 doesn't mention them. – Peilonrayz Nov 2 '17 at 13:28
• @Peilonrayz thanks a lot for the insight! I've done a fair share of Scala so they are quite natural to me, but I'll start using comprehensions instead. – Nico Nov 2 '17 at 13:36

Maybe this? I should say that this works in python 3.6.

The following code creates a list of tuples from the elements of 'lstA' and 'lstB' excluding the tuple that would contain the offending element. The zip(*[]) unpacks the list and then zips the resulting tuples thus creating the desired groups. Please see this example:

l = [('a', 1), ('b', 2)]

# the star operator is doing the job of the following two lines
# it could be: l1, l2 = [*l]
l0 = l[0]
l1 = l[1]

print(list(zip(l0,l1)))


Then the list() converts the tuples to lists.

Here is the code:

lstA = ['good','good2', '']
lstB = [1,2,3]

lstA, lstB = list(zip(*[(st, lstB[idx]) for idx, st in enumerate(lstA) if st != '']))


Or you can just change the line that creates 'lstB' in your code. The difference here is the use of enumerate() which gives as the index of each element of 'lstA'. As the elements that you want to keep have the same index in both lists, we keep the elements of 'lstB' that correspond to the elements of 'lstA' and are not the undesirable empty string ''.

lstA = ['good','good2', '']
lstB = [1,2,3]

lstB = [lstB[idx] for idx, st in enumerate(lstA) if st != '']
lstA = [st for st in lstA if st != '']

• I think your second solution is not working well, since, if we have '' in the middle of lstA as ['good', '' , 'good2'] , follow your routine, we would have lstA = ['good','good2'], but lstB would be [1,2] but acctually we want lstB to be [1,3]. – YoarkYANG Nov 2 '17 at 9:43
• No it works as expected. With the help of enumerate() we make sure that we work on the same index in both lists. – Iosif Serafeimidis Nov 2 '17 at 9:54
• But I have runned your code with lstA = ['good', '', 'good2'], lstB = [1,2,3] , for the first one, the answer is ('good', 'good2') (1,3), for the second one: ['good', 'good2'] [1,2]. I mean, in your second solution, the '' has been removed first from lstA in line4 – YoarkYANG Nov 2 '17 at 10:44
• Yes you are right, I am sorry. While trying to format the answer I pasted the line lstA = [st for st in lstA if st != ''] after the line lstB = [lstB[idx] for idx, st in enumerate(lstA) if st != '']. That way there is no '' in 'lstA' and the result is different. I fixed it now. – Iosif Serafeimidis Nov 2 '17 at 11:44
• Yes, thanks for answering, enumerate() is indeed useful in this kind of problem – YoarkYANG Nov 2 '17 at 11:48

You can create a boolean list depending upon the value you want to keep in list A and then filter the lists based on this new Boolean list.

lstA = ['good','good2', '']
lstB = [1,2,3]

filter_list=[element!='' for element in lstA]


In this case the filter_list will have values like [True, True, False]. We can use this to filter any list using the itertools.compress function

updated_lstA = list(itertools.compress(lstA,filter_list))


result:

['good', 'good2']


and you can filter for any lists, for example lstB would look like this:

updated_lstB = list(itertools.compress(lstB,filter_list))


result:

[1, 2]