dictionary comparing int keys and joins their values if two key are within a certain distance
Peter Otten
__peter__ at web.de
Wed Nov 8 12:11:58 EST 2017
Daiyue Weng wrote:
> I have a nested dictionary of defaultdict(dict) whose sub dict have int
> keys and lists (list of ints) as values,
>
> 'A' = {2092: [1573], 2093: [1576, 1575], 2094: [1577], 2095:
> [1574]}'B' = {2098: [1], 2099: [2, 3], 2101: [4], 2102: [5]}'C' =
> {2001: [6], 2003: [7, 8], 2004: [9], 2005: [10]}
>
> I union two list values if the difference of their sub keys equals to 1
> under the same outer key e.g. A, and put the joined lists into another
> list. So this list will look like,
>
> [1573, 1576, 1575, 1577, 1574][1, 2, 3][4, 5][6][7, 8, 9, 10]
>
> here since 2092, 2093, 2094, 2095 are consecutive by 1, their values are
> put into a list [1573, 1576, 1575, 1577, 1574].
>
> based on Detecting consecutive integers in a list
> <https://stackoverflow.com/questions/2361945/detecting-consecutive-> integers-in-a-list>,
> a simple solution can be built when the distance between two
> neighbouring sub keys is set to 1.
>
> results = []for key, sub_dict in d.items():
> sub_dict_keys = sorted(sub_dict.keys())
> for k, g in groupby(enumerate(sub_dict_keys), lambda ix: ix[0] -
> ix[1]):
> consecutive_keys = list(map(itemgetter(1), g))
> val_list = []
>
> for dict_key in consecutive_keys:
> val_list.extend(sub_dict[dict_key])
>
> results.append(val_list)
> print(results)
>
> , however, the code can only work when the difference between two keys is
> 1, I am wondering how to make the code account for an arbitrary distance,
> e.g. the distance between two consecutive keys are less than or equal to 2
> or 3, ... e.g. set the distance to 2,
>
> 'A' = {2092: [1573], 2093: [1576, 1575], 2095: [1577], 2097:
> [1574]}'B' = {2098: [1], 2099: [2, 3], 2101: [4], 2102: [5]}'C' =
> {2001: [6], 2003: [7, 8], 2008: [9], 2009: [10]}
>
> the result list will look like,
>
> [1573, 1576, 1575, 1577, 1574][1, 2, 3, 4, 5][6, 7, 8][9, 10]
There's a lot of noise in your question. The actual problem has nothing to
do with dictionaries, it's about dividing a list into groups.
The answer boils down to building the groups by identifying gaps between
them instead of calculating a key that is common to the group. To find a gap
you need two adjacent items, and while you can get those by combining tee
and zip, or by constructing a stateful key function that remembers the
previous value I prefer to start from scratch, with the grouped() generator
replacing itertools.groupby():
$ cat group_neighbors_simple.py
from itertools import groupby
def grouped(items, is_neighbor):
items = iter(items)
try:
prev = next(items)
except StopIteration:
return
group = [prev]
for value in items:
if is_neighbor(prev, value):
group.append(value)
else:
yield group
group = [value]
prev = value
yield group
sample = [1, 1, 2, 4, 6, 7, 6]
print([
[v for i, v in group] for key, group in
groupby(enumerate(sample), lambda iv: iv[0] - iv[1])
])
print(list(grouped(sample, lambda a, b: b - a == 1)))
print(list(grouped(sample, lambda a, b: b - a == 2)))
print(list(grouped(sample, lambda a, b: abs(b - a) < 2)))
$ python3 group_neighbors_simple.py
[[1], [1, 2], [4], [6, 7], [6]]
[[1], [1, 2], [4], [6, 7], [6]]
[[1], [1], [2, 4, 6], [7], [6]]
[[1, 1, 2], [4], [6, 7, 6]]
More information about the Python-list
mailing list