Amith Kotian
Amith Kotian

Reputation: 440

To retrieve data from list where it contains dictionary as its values (python)

I am newbie to python, trying to understand the concepts. I am trying to traverse a list, where inside list, I have kept dictionary data set which are initialized. I have defined function to traverse and the retrieve data.

Initially first key and value will be assigned to activeConfiguration list i,e activeConfiguration = ['Mammals','dogs'] and this activeConfiguration is passed as an param for getNextConfig(data, activeConfiguration) function along with entity data.

My goal is that after some certain steps when I make function call getNextConfig(data, activeConfiguration) it should retrieve next value for from the list for the particular key. the expected out I have specified below.

My code has bug, please help me to fix and to get desired result. Thanks for the help in advance.

#Entity data initialization

vertebrateAnimalsDict = [
   
    {
        "Reptiles": "Snakes, lizards, crocodiles, alligators, turtles"
    },
    
    {
        "Mammals": "dogs, cats, horses, duckbill platypuses, kangaroos, dolphins, whales"
    },

    {
        "Minibeasts": "Insects, spiders, crustaceans"
    }
]

My function calls :

activeConfiguration = ['Mammals','dogs']

activeConfiguration = getNextConfig(vertebrateAnimalsDict, activeConfiguration)
print(activeConfiguration)

#some tasks in between
 ...
activeConfiguration = getNextConfig(vertebrateAnimalsDict, activeConfiguration)
print(activeConfiguration)

#some other tasks inbetween
...
activeConfiguration = getNextConfig(vertebrateAnimalsDict, activeConfiguration)
print(activeConfiguration)            

My CODE :

#!/usr/bin/env python
   
def getNextConfig(data, activeConfiguration):
    key_count=len([ele for ele in data if isinstance(ele,dict)])
    val_index=-1   
    for dic in data:   
        for k,v in dic.items(): 
            if k==activeConfiguration[0]:                
                key_index=next((i for i,d in enumerate(data) if k in d), None)
                v=data[key_index][k]
                v = v.split(',')                
                val_index=v.index(activeConfiguration[1])
                if val_index != (len(v)-1):                    
                    return [k,v[val_index+1]]
                elif key_index==(key_count-1) and val_index == (len(v)-1):
                    return []
                else:
                    val_index=0
                    key_index=key_index+1
                    break
                
            if val_index==0:
                v=data[key_index][k]
                v = v.split(',')
                return [k,v[val_index]] 
            else:
                continue 

                       

My Expected Output result :-

Reptiles : Snakes
Reptiles : lizards
Reptiles : crocodiles
Reptiles : alligators
Reptiles : turtles
Mammals  : dogs
Mammals  : cats
and so on ...

Upvotes: 0

Views: 165

Answers (2)

Rawson
Rawson

Reputation: 2787

It would be simple to do the following:

Create one dictionary from the list of dictionaries:

dict1 = {k: v.split(", ") for x in vertebrateAnimalsDict for k, v in x.items()}

EDIT:

Convert this to a series and explode (so each item in the list of values is on a different row):

pairs = pd.Series(dict1).explode()

This small function:

def getNextConfig(pair):
    # get list of bools for whether item matches, and "shift"
    x = pairs[[False] + list(pairs == pair[1])[:-1]]
    # print the pair, for example
    print([x.index.item(), x.item()])
    # return the pair
    return [x.index.item(), x.item()]

Then running the code from the start:

pair = ["Reptiles", "Snakes"]
pair = getNextConfig(pair) # repeat this line to the end (and error on the very last, where it cannot continue)

And the old answer's loop, just in case you decide that you will loop through every combination or want to do this in the future:

for k, v in dict1.items():
    for idx in range(len(v)):
        print([k, v[idx]])
        
        # the other code here...

EDIT 2:

Without the use of Pandas, you can instead "flip" the dictionary:

pairs = {}

for k, v in dict1.items():
    for idx in range(len(v)):
        pairs.update({v[idx]: k})

As all the items in the lists for reptiles, mammals, and minibeasts will be unique, you can change the values to keys and these three categories to values.

Then when calling the function you can reverse these when returning the pair (I have written a list comprehension to search the list of keys, "animals", instead of searching for values in a Pandas Series):

def getNextConfig(pair):
    # get list of bools for whether item matches, and "shift"
    p = [i+1 for i, y in enumerate(pairs.keys()) if y==pair[1]][0]
    if len(pairs.keys()) <= p:
        # print statement if out of items
        print("Previous pair was last pair")
        # return same pair (i.e. the last pair)
        return pair
    # animal
    x = list(pairs.keys())[p]
    # print the pair
    print([pairs[x], x])
    # return the pair
    return [pairs[x], x]

Note that I have included an if statement for the last pair so that you a specific message can be written.

Upvotes: 1

Nick
Nick

Reputation: 147196

If I understand your question correctly, you could just use a generator to iterate the values:

def getNextConfig(data):
    for dic in data:
        for key, value in dic.items():
            values = value.split(', ')
            for v in values:
                yield key, v

You might then loop over it like this:

configs = getNextConfig(vertebrateAnimalsDict)
for k, v in configs:
    print(f'{k} : {v}')

Output (for your sample data):

Reptiles : Snakes
Reptiles : lizards
Reptiles : crocodiles
Reptiles : alligators
Reptiles : turtles
Mammals : dogs
Mammals : cats
Mammals : horses
Mammals : duckbill platypuses
Mammals : kangaroos
Mammals : dolphins
Mammals : whales
Minibeasts : Insects
Minibeasts : spiders
Minibeasts : crustaceans

Or to match your code style in the question, we use next to fetch the next value from the generator:

configs = getNextConfig(vertebrateAnimalsDict)
activeConfiguration = next(configs, None)
if activeConfiguration is not None:
    # do something with it

Note we supply a default value to next to avoid a StopIteration error.

Upvotes: 1

Related Questions