Iterating through two lists with 'if... or' statement

Viewed 38

I have 3 lists.

values_to_add = []
values_to_remove = []
values_to_keep = []

Only one of the lists is populated at a time. If one of two of the lists is populated, I would like to perform this action:

if values_to_remove or values_to_keep:
    if values_to_remove:
        for value in values_to_remove:
            try:
                value_object.related_value.get(value=value)
            except exceptions.ObjectDoesNotExist:
                raise UnableToUpdate("These values are not related!")
    elif values_to_keep:
        for value in values_to_keep:
            try:
                value_object.related_value.get(value=value)
            except exceptions.ObjectDoesNotExist:
                raise UnableToUpdate("These values are not related!")        

However this code seems clunky and I am sure there is a more concise way to write this as it is literally repeating code. Any suggestions?

3 Answers
if values_to_remove or values_to_keep:
    for value in (values_to_remove if len(values_to_remove) else values_to_keep):
        try:
            value_object.related_value.get(value=value)
        except exceptions.ObjectDoesNotExist:
            raise UnableToUpdate("These values are not related!")

You could take the upper if statement away and it probably wouldn't have any consequences for the functionality of the code. This would make it cleaner and a bit faster.

if values_to_remove:
    for value in values_to_remove:
        try:
            value_object.related_value.get(value=value)
        except exceptions.ObjectDoesNotExist:
            raise UnableToUpdate("These values are not related!")
elif values_to_keep:
    for value in values_to_keep:
        try:
            value_object.related_value.get(value=value)
        except exceptions.ObjectDoesNotExist:
            raise UnableToUpdate("These values are not related!")

You could also use a matrix (2D array) to iterate trough all your arrays, like this:

values = [
    [], #values_to_keep
    [] #values_to_remove
]

for array in values:
    if array:
        for value in values_to_remove:
            try:
                value_object.related_value.get(value=value)
            except exceptions.ObjectDoesNotExist:
                raise UnableToUpdate("These values are not related!")
        break

Though I would only recommend doing this with a lot more arrays, since otherwise it makes your code more complicated than it needs to be.

If you know that only one list is populated then you can just run the two loops in sequence:

for value in values_to_remove:
    # body elided 

for value in values_to_keep:
    # body elided

or since the bodies are the same:

def body(value):
    # body elided
for value in values_to_remove + values_to_keep:
    body(value)
Related