nana
nana

Reputation: 59

how to make take two lists and remove elements based on another list?

I have three lists. Two lists of string, and one list of float. I used zip to match one list of string and float together that are the same length to make a new string. Basically:

letters1 = ['a', 'b', 'c', 'd', 'e']
numbers = [0.0, 3.0, 5.0, 10.0, 28.0]
letters2 = ['a', 'c', 'e']
letnum = [i for i in zip(letters1, numbers)]

This gets me: [('a', 0.0), ('b', 3.0), ('c', 5.0), ('d', 10.0), ('e', 28.0)]

I want to use the other list to get only [0.0, 5.0, 28.0], but I don't know how to return a list of float like that.

I tried using [x for x in letnum if x in letters2] but that gave me [].

I also know letnum = [i for _, i in zip(letters1, numbers)] will get me [0.0, 3.0, 5.0, 10.0, 28.0] but I don't know if that does anything.

Any help would be appreciated!

Upvotes: 3

Views: 69

Answers (5)

ggorlen
ggorlen

Reputation: 57289

If you anticipate large lists, here's a linear solution using a lookup dictionary to enable grabbing a float for each element in letters2 in constant time instead of repeatedly iterating in a nested loop. Total time complexity is O(len(letters) + len(letters2)) which is optimal:

>>> letters1 = ['a', 'b', 'c', 'd', 'e']
>>> numbers = [0.0, 3.0, 5.0, 10.0, 28.0]
>>> letters2 = ['a', 'c', 'e']
>>> lookup = {x: y for x, y in zip(letters1, numbers)}
>>> [lookup[x] for x in letters2 if x in lookup]
[0.0, 5.0, 28.0]

The reason your original attempt doesn't work is [x for x in letnum if x in letters2] tries to find a whole tuple x in letters2 which only contains strings.

Upvotes: 1

Karl Knechtel
Karl Knechtel

Reputation: 61643

Let's consider the entire process at once (edited slightly because I misunderstood the requirement)

for each of the letter and number pairs that we get by zipping together letters1 and numbers, we want: the number, but only if the letter was in letters2.

So, we write it exactly like that, except that the element description goes at the front.

[number for letter, number in zip(letters1, numbers) if letter in letter2]

To cover your attempts:

I tried using [x for x in letnum if x in letters2] but that gave me [].

Yes, because x is one of the pairs, and letters2 doesn't contain those pairs. You can fix this as in @vaichidrewar's answer by extracting the letter, x[0], for the comparison. Similarly, x is one of the pairs, and you only want the number, so x[1] extracts the number.

I also know letnum = [i for _, i in zip(letters1, numbers)] will get me [0.0, 3.0, 5.0, 10.0, 28.0] but I don't know if that does anything.

It's a start, in the sense that you are using unpacking for the zip results to give separate names to the elements of each pair that you get. By convention, we use _ to refer to values that we don't care about; but you do care about both values (because you want the letter for the condition).

Upvotes: 1

tshiono
tshiono

Reputation: 22087

Would you try the following:

letters1 = ['a', 'b', 'c', 'd', 'e']
numbers = [0.0, 3.0, 5.0, 10.0, 28.0]
letters2 = ['a', 'c', 'e']

d = {}
for i in range(len(letters1)):
    d[letters1[i]] = numbers[i]
letnum = [d[x] for x in letters2]
print(letnum)

Output:

[0.0, 5.0, 28.0]

Upvotes: 1

Davinder Singh
Davinder Singh

Reputation: 2162

convert zip object into list and access 0, 2, 5 index using range(0, len(numbers), 2)

letters1 = ['a', 'b', 'c', 'd', 'e']
numbers = [0.0, 3.0, 5.0, 10.0, 28.0]
letters2 = ['a', 'c', 'e']
letnum = [list(zip(letters1, numbers))[i] for i in range(0,len(numbers), 2)]

print(letnum)

Methiod-2

letnum = [i for i in zip(letters1, numbers) if i[0] in letters2]

Upvotes: 0

vaichidrewar
vaichidrewar

Reputation: 9621

Each element in letnum is a tuple which is a pair of a letter and a float. If you take the first element of the tuple and then check for existence in the letters2 list you will find a match.

[x for x in letnum if x[0] in letters2] 

x[0] is taking the first element of the tuple.

Upvotes: 3

Related Questions