Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check that list contains the elements of all the types present in another list

I have two Python lists: components and signature. I want to check whether all the types listed in signature match at least one of the elements in the component list.

Here, the signature matches the component list, because there is both a string and a float in components:

signature = [float, str]
components = [1.0, [], 'hello', 1]

Here, signature does not match components, because there is no list type.

signature = [float, list]
components = ['apple', 1.0]

How can I express this condition in Python 3?

like image 784
Ashley Avatar asked Jan 28 '23 15:01

Ashley


2 Answers

You may use combination of all() and any() with nested generator expression to achieve this. Here I am using isinstance() to check for each type in your signature list matches with the object in components list. Using this, your custom function will be as:

def check_match(signature, components):
    return all(any(isinstance(c, s) for c in components) for s in signature)

Sample Run:

# Example 1: Condition is matched - returns `True`
>>> signature = [str, int]
>>> components = [1, 'hello', []]
>>> check_match(signature, components)
True

# Example 2: Condition is not matched - returns `False`
>>> signature = [float, list]
>>> components = ['apple', 1.0]
>>> check_match(signature, components)
False

Explanation: Above nested generator expression is comprised of two parts. First part is:

all(...`any()` call... for s in signature)

Here, I am iterating signature list to get each element s present in it. all() will return True only when all the ...any() call... logic will return True. Else it will return False.

Second is the ...any() call... generator expression as:

any(isinstance(c, s) for c in components)

Here, for each element c in components list, I am checking whether the type of c is s from the external generator comprehension. If any of the type matches, any(..) will return True. If none of c matches the condition, any(...) will return False.

like image 138
Moinuddin Quadri Avatar answered Jan 31 '23 05:01

Moinuddin Quadri


Another approach is to calculate the difference between the set of types used in components and those you have in signature.

unique_signatures = set(signature)
components_type = set(map(type, components))

types_not_used = unique_signatures.difference(components_type)

if len(types_not_used)==0:
    print('All types used')
else:
    print('Types not used:', types_not_used)

I believe there are two main advantages with this solution:

  1. More efficient if your components list was long with many duplicate types, as you reduce the number of comparisons
  2. How precise do you want to be in matching the class? Should subclasses pass the test? For example, isinstance(1, object) is True: is this behavior desirable to you?

Using the function provided by the (very good) answer of @Moinuddin, you have the following:

check_match([object], [1, 2.0, 'hello'])
Out[20]: True

while my answer would check object versus ['int', 'float', 'str'] finding no match.

like image 39
FLab Avatar answered Jan 31 '23 06:01

FLab