Auscoi
Auscoi

Reputation: 33

Most pythonic for selecting one entry from a list of dicts based on dict key?

So let's say I have AllData, a list of nested dicts (let's pretend there are thousands of entries) but I'm only looking for a single entry.

AllData = [
    { "EntryA" : {"A Key":"A Value"} },
    { "EntryB" : {"B Key":"B Value"} },
    { "EntryC" : {"C Key":"C Value"} }
]

Currently I'm just looping through it and breaking once I find the matching key.

MyKey = "EntryB"
FoundData = {}
for item in AllData:
    for key,data in item.items():
        if MyKey.lower() == key.lower():
            FoundData = data
            break
print(FoundData)

However, being a Python enthusiast I know there's a more elegant way to do this. I've struggled a bit with proper list comprehension techniques but I'm trying! Below is the best I've been able to come up with that gathers this data in a single line but I'm wondering if there is an even MORE elegant solution to this problem.

MyKey = "EntryB"    
FoundData = [x for x in AllData if str(list(x.items())[0][0]).lower() == MyKey.lower()][0][MyKey]
print(FoundData)

Any insight would be greatly appreciated :)

Upvotes: 2

Views: 67

Answers (3)

AMC
AMC

Reputation: 2702

I don't think a list comprehension is the appropriate way of doing this, since you only want the first match.

all_data = [
    {"EntryA": {"A Key": "A Value"}},
    {"EntryB": {"B Key": "B Value"}},
    {"EntryC": {"C Key": "C Value"}}
]

targ_key = "EntryB"

found_data = None

for curr_dict in all_data:
    if found_data := curr_dict.get(targ_key):
        break

print(found_data)

I'm still not entirely sure if using an assignment expression here is worth it, it might make it more difficult to understand.

Here is a version without the assignment expression:

all_data = [
    {"EntryA": {"A Key": "A Value"}},
    {"EntryB": {"B Key": "B Value"}},
    {"EntryC": {"C Key": "C Value"}}
]

targ_key = "EntryB"

found_data = None

for curr_dict in all_data:
    curr_data = curr_dict.get(targ_key)
    if curr_data is not None:
        found_data = curr_data
        break

print(found_data)

Upvotes: 1

unil
unil

Reputation: 194

You could use filter(), depending on the contens of MyKey, it will look something as:

AllData = [
    { "EntryA" : {"A Key":"A Value"} },
    { "EntryB" : {"B Key":"B Value"} },
    { "EntryC" : {"C Key":"C Value"} }
]
MyKey = "EntryB"
found = list(filter(lambda x: MyKey in x.keys(), AllData))[0][MyKey]
print(found)

Upvotes: 0

Andrej Kesely
Andrej Kesely

Reputation: 195553

If you're using Python 3.8+ you can combine assignment expression (:=) and any() (any() will break when you find first valid element):

AllData = [
    { "EntryA" : {"A Key":"A Value"} },
    { "EntryB" : {"B Key":"B Value"} },
    { "EntryC" : {"C Key":"C Value"} }
]

if any((found:=d) for d in AllData if "EntryB" in d):
    print(found)

Prints:

{'EntryB': {'B Key': 'B Value'}}

Upvotes: 3

Related Questions