Tom
Tom

Reputation: 681

Check if value exists in nested lists

in my list:

animals =  [ ['dog', ['bite'] ],
             ['cat', ['bite', 'scratch'] ],
             ['bird', ['peck', 'bite'] ], ]

add('bird', 'peck')
add('bird', 'screech')
add('turtle', 'hide')

The add function should check that the animal and action haven't been added before adding them to the list. Is there a way to accomplish this without nesting a loop for each step into the list?

Upvotes: 2

Views: 4644

Answers (6)

John Fouhy
John Fouhy

Reputation: 42193

While I agree with the others re. your choice of data structure, here is an answer to your question:

def add(name, action):
    for animal in animals:
        if animal[0] == name:
            if action not in animal[1]:
                animal[1].append(action)
            return
    else:
        animals.append([name, [action]])

The for loop is an inevitable consequence of your data structure, which is why everyone is advising you to consider dictionaries instead.

Upvotes: 0

recursive
recursive

Reputation: 86124

You're using the wrong data type. Use a dict of sets instead:

def add(key, value, userdict):
    userdict.setdefault(key, set())
    userdict[key].add(value)

Usage:

animaldict = {}
add('bird', 'peck', animaldict)
add('bird', 'screech', animaldict)
add('turtle', 'hide', animaldict)

Upvotes: 6

David Z
David Z

Reputation: 131640

Based on recursive's solution, in Python 2.5 or newer you can use the defaultdict class, something like this:

from collections import defaultdict

a = defaultdict(set)

def add(animal, behavior):
    a[animal].add(behavior)

add('bird', 'peck')
add('bird', 'screech')
add('turtle', 'hide')

Upvotes: 4

elo80ka
elo80ka

Reputation: 15845

animals_dict = dict(animals)

def add(key, action):
    animals_dict.setdefault(key, [])
    if action not in animals_dict[key]:
        animals_dict[key].append(action)

(Updated to use setdefault - nice one @recursive)

Upvotes: 0

Georg Schölly
Georg Schölly

Reputation: 126145

You really should use a dictionary for this purpose. Or alternatively a class Animal.

You could improve your code like this:

if not any((animal[0] == "bird") for animal in animals):
    # append "bird" to animals

Upvotes: 0

Jarret Hardie
Jarret Hardie

Reputation: 98002

While it is possible to construct a generic function that finds the animal in the list using a.index or testing with "dog" in animals, you really want a dictionary here, otherwise the add function will scale abysmally as more animals are added:

animals = {'dog':set(['bite']),
           'cat':set(['bite', 'scratch'])}

You can then "one-shot" the add function using setdefault:

animals.setdefault('dog', set()).add('bite')

It will create the 'dog' key if it doesn't exist, and since setdefault returns the set that either exists or was just created, you can then add the bite action. Sets ensure that there are no duplicates automatically.

Upvotes: 4

Related Questions