Zusman
Zusman

Reputation: 666

find an item inside a list of dictionaries

Say I have a list of dictionaries. each dict in the list has 3 elements. Name, id and status.

list_of_dicts = [{'id':1, 'name':'Alice', 'status':0},{'id':2, 'name':'Bob', 'status':0},{'id':3, 'name':'Robert', 'status':1}]

so I get:

In[20]: print list_of_dicts
Out[20]: 
[{'id': 1, 'name': 'Alice', 'status': 0},
 {'id': 2, 'name': 'Bob', 'status': 0},
 {'id': 3, 'name': 'Robert', 'status': 1}]

If i recieve a name, how can I get its status without iterating on the list?
e.g. I get 'Robert' and I want to output 1.
thank you.

Upvotes: 5

Views: 11942

Answers (5)

RoadRunner
RoadRunner

Reputation: 26315

It's not possible to do this without iteration.

However, but you can transform you dictionary into a different data structure, such as a dictionary where names are the keys:

new_dict = {person["name"]: {k: v for k, v in person.items() if k != "name"} for person in list_of_dicts}

Then you can get the status like so:

new_dict["Robert"]["status"]
# 1

Additionally, as @tobias_k mentions in the comments, you can keep the internal dictionary the same:

{person["name"]: person for person in list_of_dicts}

The only issue with the above approaches is that it can't handle multiple names. You can instead add the unique id into the key to differentiate between names:

new_dict = {(person["name"], person["id"]): person["status"] for person in list_of_dicts}

Which can be called like this:

new_dict["Robert", 3]
# 1

Even though it takes extra computation(only once) to create these data structures, the lookups afterwards will be O(1), instead of iterating the list every time when you want to search a name.

Upvotes: 5

Rarblack
Rarblack

Reputation: 4664

Your list_of_dicts cannot be reached without a loop so for your desire your list should be modified a little like 1 dict and many lists in it:

list_of_dicts_modified = {'name':['Alice', 'Bob', 'Robert'],'id':[1, 2, 3], 'status': [0, 0, 1]}
index = list_of_dicts_modified['name'].index(input().strip())
print('Name: {0} ID: {1} Status: {2}'.format(list_of_dicts_modified['name'][index], list_of_dicts_modified['id'][index], list_of_dicts_modified['status'][index]))

Output:

C:\Users\Documents>py test.py
Alice
Name: Alice ID: 1 Status: 0

Upvotes: 2

progmatico
progmatico

Reputation: 4964

As you found you have to iterate (unless you are able to change your data structure to an enclosing dict) why don't you just do it?

>>> [d['status'] for d in list_of_dicts if d['name']=='Robert']
[1]

Despite this, I recommend considering a map type (like dict) every time you see some 'id' field in a proposed data structure. If it's there you probably want to use it for general identification, instead of carrying dicts around. They can be used for relations also, and transfer easily into a relational database if you need it later.

Upvotes: 4

frankegoesdown
frankegoesdown

Reputation: 1924

for example you can use pandas

import pandas as pd
list_of_dicts = [{'id':1, 'name':'Alice', 'status':0},{'id':2, 'name':'Bob', 'status':0},{'id':3, 'name':'Robert', 'status':1}]

a = pd.DataFrame(list_of_dicts)
a.loc[a['name'] == 'Robert']

and play with dataframes its very fast because write on c++ and easy (like sql queries)

Upvotes: 4

Gsk
Gsk

Reputation: 2945

I don't think you can do what you ask without iterating through the dictionary:
Best case, you'll find someone that suggests you a method that hides the iteration.

If what really concerns you is the speed, you may break your iteration as soon as you find the first valid result:

for iteration, elements in enumerate(list_of_dicts):
    if elements['name'] == "Robert":
        print "Elements id: ", elements['id']
        break
print "Iterations: ", iteration

# OUTPUT: Elements id: 3, Iterations: 1

Note that numbers of iteration may vary, since dictionaries are not indexed, and if you have more "Roberts", only for one the "id" will be printed

Upvotes: 3

Related Questions