vishal babu
vishal babu

Reputation: 73

Splitting list of dictionary into sublists after the occurence of particular key of dictionary

I have list of dictionaries. These dictionaries basically have just one key-value each.

For example:

lst = [{'x': 23}, {'y': 23432}, {'z': 78451}, {'a': 564}, {'x': 45},
       {'y': 7546}, {'a': 4564}, {'x': 54568}, {'y': 4515}, {'z': 78457}, 
       {'b': 5467}, {'a': 784}]

I am trying to divide the list of dictionaries lst into sublists after every occurrence of a dictionary with a specific key "a".

I tried using other ways that I saw on the internet but as I am new to python, I am not able to understand them and get the desired result. I want the final result to look like:

final_lst = [
    [{'x': 23}, {'y': 23432}, {'z': 78451}, {'a': 564}],
    [{'x': 45}, {'y': 7546}, {'a': 4564}],
    [{'x': 54568}, {'y': 4515}, {'z': 78457}, {'b': 5467}, {'a': 784}]],
]

Upvotes: 7

Views: 1279

Answers (5)

Danil Speransky
Danil Speransky

Reputation: 30453

Here is a straightforward solution:

result = []

for item in lst:
    if not result or 'a' in result[-1][-1]:
        result.append([])

    result[-1].append(item)

Upvotes: 3

zipa
zipa

Reputation: 27869

Just to add to bunch, this would be solution based on x instead of a:

lst = [{'x':23}, {'y':23432}, {'z':78451}, {'a':564}, {'x':45}, {'y':7546},
       {'a':4564}, {'x':54568}, {'y':4515}, {'z':78457}, {'b':5467}, {'a':784}]

result = []
temp = []

breaker = 'x'

for i, item in enumerate(lst):
    if item.keys() != [breaker]:  
        temp.append(item)
    else:
        if i == 0:
            temp.append(item)
        else:
            result.append(temp)
            temp = [item]
    if i == len(lst)-1:
        result.append(temp)

Upvotes: 0

user2390182
user2390182

Reputation: 73460

You can zip together pairs of delimiting indexes of each partition from a conditional comprehension. Then you comprehend the appropriate slices:

splits = [i for i, d in enumerate(lst, 1) if 'a' in d]
final_lst = [lst[start: end] for start, end in zip([0] + splits, splits)]
# final_lst
# [[{'x': 23}, {'y': 23432}, {'z': 78451}, {'a': 564}], [{'x': 45}, {'y': 7546}, {'a': 4564}], [{'x': 54568}, {'y': 4515}, {'z': 78457}, {'b': 5467}, {'a': 784}]]

Docs on enumerate, zip.

Upvotes: 1

cs95
cs95

Reputation: 402423

Let's try itertools.groupby.

import itertools

lst2 = []
for i, (_, g) in enumerate(itertools.groupby(lst, key=lambda x: not x.keys() - {'a'})):
     if not i % 2:
        lst2.append([])
     lst2[-1].extend(list(g))

lst2 
[[{'x': 23}, {'y': 23432}, {'z': 78451}, {'a': 564}],
 [{'x': 45}, {'y': 7546}, {'a': 4564}],
 [{'x': 54568}, {'y': 4515}, {'z': 78457}, {'b': 5467}, {'a': 784}]]

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1121744

You can use a generator that collects elements and yields when the condition is met:

def split_by_key(lst, key):
    collected = []
    for d in lst:
        collected.append(d)
        if key in d:
            yield collected
            collected = []
    if collected:  # yield any remainder
        yield collected

final_lst = list(split_by_key(lst, 'a'))

Demo:

>>> lst = [{'x': 23}, {'y': 23432}, {'z': 78451}, {'a': 564}, {'x': 45},
...        {'y': 7546}, {'a': 4564}, {'x': 54568}, {'y': 4515}, {'z': 78457},
...        {'b': 5467}, {'a': 784}]
>>> list(split_by_key(lst, 'a'))
[[{'x': 23}, {'y': 23432}, {'z': 78451}, {'a': 564}], [{'x': 45}, {'y': 7546}, {'a': 4564}], [{'x': 54568}, {'y': 4515}, {'z': 78457}, {'b': 5467}, {'a': 784}]]
>>> pprint(_)
[[{'x': 23}, {'y': 23432}, {'z': 78451}, {'a': 564}],
 [{'x': 45}, {'y': 7546}, {'a': 4564}],
 [{'x': 54568}, {'y': 4515}, {'z': 78457}, {'b': 5467}, {'a': 784}]]

Upvotes: 6

Related Questions