Splitting a dictionary by key suffixes

Question:

I have a dictionary like so

d = {"key_a":1, "anotherkey_a":2, "key_b":3, "anotherkey_b":4}

So the values and key names are not important here. The key (no pun intended) thing, is that related keys share the same suffix in my example above that is _a and _b.

These suffixes are not known before hand (they are not always _a and _b for example, and there are an unknown number of different suffixes.

What I would like to do, is to extract out related keys into their own dictionaries, and have all generated dictionaries in a list.
The output from above would be

output = [{"key_a":1, "anotherkey_a":2},{"key_b":3, "anotherkey_b":4}]

My current approach is to first get all the suffixes, and then generate the sub-dicts one at a time and append to the new list

output = list()
# Generate a set of suffixes
suffixes = set([k.split("_")[-1] for k in d.keys()])

# Create the subdict and append to output
for suffix in suffixes:
    output.append({k:v for k,v in d.items() if k.endswith(suffix)})

This works (and is not prohibitively slow or anyhting) but I am simply wondering if there is a more elegant way to do it with a list or dict comprehension? Just out of interest…

Asked By: wstk

||

Answers:

Make your output a defaultdict rather than a list, with suffixes as keys:

from collections import defaultdict
output = defaultdict(lambda: {})
for k, v in d.items():
    prefix, suffix = k.rsplit('_', 1)
    output[suffix][k] = v

This will split your dict in a single pass and result in something like:

output = {“a” : {“key_a”:1, “anotherkey_a”:2}, “b”: {“key_b”:3, “anotherkey_b”:4}}

and if you insist on converting it to a list, you can simply use:

output = list(output.values())
Answered By: Błotosmętek

You could condense the lines

output = list()

for suffix in suffixes:
    output.append({k:v for k,v in d.items() if k.endswith(suffix)})

to a list comprehension, like this

[{k:v for k,v in d.items() if k.endswith(suffix)} for suffix in suffixes]

Whether it is more elegant is probably in the eyes of the beholder.

The approach suggested by @Błotosmętek will probably be faster though, given a large dictionary, since it results in less looping.

Answered By: tfw
def sub_dictionary_by_suffix(dictionary, suffix):
    sub_dictionary = {k: v for k, v in dictionary.items() if k.endswith(suffix)}

    return sub_dictionary

I hope it helps

Answered By: Javier Segovia
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.