check if element is in anywhere the list

Question:

I have two lists:

expected = ["apple", "banana", "pear"]
actual = ["banana_yellow", "apple", "pear_green"]

I’m trying to assert that expected = actual. Even though the color is added at the end to some elements, it should still return true.

Things I tried:

for i in expected:
   assert i in actual

I was hoping something like this would work but it’s trying to match the first element apple to banana and returns false rather than checking the entire list and returns true if there is apple anywhere in the list. I was hoping someone can help?

Edit: The lists can be different lengths.

Asked By: stock_exchange

||

Answers:

Try this:

def isequal(actual: list, expected: list) -> bool:
    actual.sort()
    expected.sort()
    if len(actual) != len(expected):
        return False
    for i, val in enumerate(expected):
        if not actual[i].startswith(val):
            return False
    return True

print(isequal(actual, expected))
Answered By: Ivan Perehiniak

I suggest a custom assertion method..

This is a bit more than you need, but also a bit more flexible.

  • Order of the entries is irrelevant
  • How the color is added is irrelevant (e.g. by dash, underscore, …)

It still has the flaw that, if you have the color orange added to carot and are looking for orange, it would also assert sucessfully. For such cases you need to tailor the method to your actual needs. (e.g. replace the substring in string by string.startwith(substring) etc. However, this should give you a starting point:

def assert_matching_list_contents(expected: list, actual: list) -> None:
    if len(expected) != len(actual):
        raise AssertionError('Length of the lists does not match!')

    for expected_value in expected:
        if not any(expected_value in entry for entry in actual):
            raise AssertionError(f'Expected entry "{expected_value}" not found')

expectation = ["apple", "banana", "pear"]
current = ["banana_yellow", "apple", "pear_green"]
assert_matching_list_contents(expectation, current)
Answered By: Cpt.Hook
expected = ["apple", "banana", "pear"]
actual = ["banana_yellow", "apple", "pear_green", 'orange']

for act in actual:
    if not act.startswith(tuple(expected)):
        print(act)
>>>
orange

If you want it to work in the opposite way,

expected = ["apple", "banana", "pear", 'grapes']
actual = ["banana_yellow", "apple", "pear_green", 'orange']
expected_ = set(expected)
for act in actual:
    for exp in expected:
        if act.startswith(exp):
            expected_.discard(exp)
            break
assert not(expected_), f"{expected_} are not found in actual and " + f"{set(expected)-expected_} are found in actual"
>>>
AssertionError: {'grapes'} are not found in actual and {'apple', 'pear', 'banana'} are found in actual

Another way,

expected = ["apple", "banana", "pear", 'grapes']
actual = ["banana_yellow", "apple", "pear_green", 'orange']
for exp in expected:
    assert [exp for act in actual if act.startswith(exp)], f'{exp} not found'
>>>
AssertionError: grapes not found
Answered By: Ricardo

You can use .startswith, along with sorted lists to find it.

expected = ["apple", "banana", "pear"]
actual = ["banana_yellow", "apple", "pear_green"]
expected.sort() # just looking for prefixes
actual.sort()
count = 0
for i in actual:
    if i.startswith(expected[count]): # prefix matches!
        count+=1 # move to next prefix
if count != len(expected): # since it didn't find all expected
    print("Nope!")
    assert False

It works because it just skips extras in actual, but count gets stuck if it can’t find the prefix in actual, leading count to never reach the end of expected.

Answered By: kenntnisse

Ricardo answer was able to resolve the issue I’ve been having. I tested it with multiple different lists and it works great, thank you everyone for the help.

Answered By: stock_exchange
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.