简体   繁体   中英

Split a list of dictionary if the value is empty?

I want to split a list of dictionary if the value is empty and create new list of list.

Input :

[{'k':'a'},{'k':'b'},{'k':''},{'k':'d'},{'k':''},{'k':'f'},{'k':'g'}]

Output :

[[{'k': 'a'}, {'k': 'b'}, {'k': ''}], [{'k': 'd'}, {'k': ''}], [{'k': 'f'}, {'k': 'g'}]]

I have tried using loop, if and its working fine.

sub_header_list = [{'k':'a'},{'k':'b'},{'k':''},{'k':'d'},{'k':''},{'k':'f'},{'k':'g'}]
index_data = [] ; data_list = []
for i in sub_header_list:
    index_data.append(i)
    if i['k'] == '':
        data_list.append(index_data)
        index_data = [] 
print(data_list+[index_data])

[[{'k': 'a'}, {'k': 'b'}, {'k': ''}], [{'k': 'd'}, {'k': ''}], [{'k': 'f'}, {'k': 'g'}]]

Is there any pythonic way to achieve the same, i mean by using in-built functions or something else ?

You can use a groupby :

from itertools import groupby, chain


l = [{'k':'a'},{'k':'b'},{'k':''},{'k':'d'},{'k':''},{'k':'f'},{'k':'g'}]

grps = groupby(l, lambda d: d["k"] == "")

print([list(chain(*(v, next(grps, [[], []])[1]))) for k, v in grps if k])

Output:

[[{'k': 'a'}, {'k': 'b'}, {'k': ''}], [{'k': 'd'}, {'k': ''}], [{'k': 'f'}, {'k': 'g'}]]

Or use a generator function:

def grp(lst, ):
    temp = []
    for dct in lst:
        # would catch None, 0, for just empty strings use if dct["k"] == "".
        if not dct["k"]: 
            temp.append(dct)
            yield temp
            temp = []
        else:
            temp.append(dct)
    yield temp

Which gives you the same output:

In [9]: list(grp(l))
Out[9]: 
[[{'k': 'a'}, {'k': 'b'}, {'k': ''}],
 [{'k': 'd'}, {'k': ''}],
 [{'k': 'f'}, {'k': 'g'}]]

The generator function is by far the most efficient approach.

In [8]: l = [{'k':'a'}, {'k':'b'}, {'k':''}, {'k':'d'}, {'k':''}, {'k':'f'}, {'k':'g'}]

In [9]: l = [dict(choice(l)) for _ in range(100000)]

In [10]: timeit list(grp(l))
10 loops, best of 3: 19.5 ms per loop

In [11]: %%timeit
index_list = [i + 1 for i, x in enumerate(l) if x == {'k': ''}]
[l[i:j] for i, j in zip([0] + index_list, index_list + [len(l)])]
   ....: 
10 loops, best of 3: 31.6 ms per loop

In [12]: %%timeit                 grps = groupby(l, lambda d: d["k"] == "")
[list(chain(*(v, next(grps, [[], []])[1]))) for k, v in grps if k]
   ....: 
10 loops, best of 3: 40 ms per loop

This is another Pythonic way of doing it:

>>> d = [{'k':'a'}, {'k':'b'}, {'k':''}, {'k':'d'}, {'k':''}, {'k':'f'}, {'k':'g'}]
>>> index_list = [i + 1 for i, x in enumerate(d) if x == {'k': ''}]
>>> [d[i:j] for i, j in zip([0] + index_list, index_list + [len(d)])]
[[{'k': 'a'}, {'k': 'b'}, {'k': ''}], [{'k': 'd'}, {'k': ''}], [{'k': 'f'}, {'k': 'g'}]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM