Home > Mobile >  list comprehension to filter a list of lists
list comprehension to filter a list of lists

Time:11-29

This problem is from https://leetcode.com/problems/find-players-with-zero-or-one-losses/. Is it possible to use list comprehension in this problem to create a new list that only has the first item of every tuple that never shows up in the second item of any tuple.

For instance:

matches = [[1,3],[2,3],[3,6],[5,6],[5,7],[4,5],[4,8],[4,9],[10,4],[10,9]]

I want a new list of:

neverLost = [1, 2, 10]

I would make two lists, one for each part of the question with list comprehension and then concatenate them together afterwards for the solution. I tried using list comprehension but I'm having syntax issues

neverLost = [w for w, l in matches if w not l]

The first part w for w, l in matches works fine and will create a list of just the first item of each tuple [1, 2, 3, 5, 5, 4, 4, 4, 10, 10], but I'm struggling with the syntax and understanding of the expression to filter the "winners". Please let me know if this is even a good solution for the problem. I know I can probably do this with a dictionary, but I wanted to know if this way was also possible. Thanks!

CodePudding user response:

List comprehension works, but not optimised way to solve these sort of problems

In [48]: list(set([j[0] for j in matches if j[0] not in [i[1] for i in matches]]))
Out[48]: [1, 2, 10]

CodePudding user response:

What you did

neverLost = [w for w, l in matches if w not l]

is going to check whether the first item in that tuple is equal to the second item in that same tuple. It is not checking whether the first item is present at 2nd position in any other tuple.

You can use this -

list(set([w[0] for w in matches if w[0] not in [l[1] for l in matches]]))

CodePudding user response:

I think you need to do something like,

matches = [[1, 3], [2, 3], [3, 6], [5, 6], [5, 7], [4, 5], [4, 8], [4, 9], [10, 4], [10, 9]]

losses_dict = {}
for (_, value) in matches:
    losses_dict.setdefault(value, 0)  # key might exist already
    losses_dict[value]  = 1

final_list = [
              [k for k, _ in matches if k not in losses_dict.keys()],
              [k for k, v in losses_dict.items() if v == 1]
             ]

The dict.setdefault checks if the key already existis otherwise it appends the value 0.

CodePudding user response:

Sure, something like this is a reasonable solution:

seconds = {second for _, second in matches}
never_lost = [first for first, _ in matches if first not in seconds]
never_lost = list(dict.fromkeys(never_lost))  # idiom for removing duplicates while maintaining order

Now, if you mean only using a single list comprehension expression, then you'd have to get pretty janky:

never_lost = [
    x for x in
    {
        first: None
        for first, _ in matches 
        for seconds in [{second for _, second in matches}] 
        if first not in seconds
    }
]

I'd stick to the first approach. Not everything has to or should be a single list comprehension expression.

CodePudding user response:

neverLost = list(set(w for w, l in matches if all(w != j for i, j in matches)))

List comprehensions are good for performance but most of the time complex list comprehensions can decrease code readability.

  • Related