Splitting Dictionary Items into Smaller Dictionaries Based on Condition

Splitting dictionary items into smaller dictionaries based on condition

One way would just be to keep track of how many times you've seen a given parent. The first time you see parent 'a', you add that partial/parent pair to the first group; the second, to the second group, etc.

For example:

def split_into_groups(transactions):
counts = {}
out_groups = {}
for partial, parent in transactions:
counts[parent] = target = counts.get(parent, 0) + 1
out_groups.setdefault(target, {})[partial] = parent
return out_groups

gives me

In [9]: split_into_groups(zip(partials, parents))
Out[9]:
{1: {1: 'a', 2: 'b', 3: 'c', 4: 'd', 7: 'f'},
2: {5: 'a', 6: 'd', 8: 'c'},
3: {9: 'c', 10: 'a'}}

This uses counts.get to get a default value of 0 if the count isn't present yet, and out_groups.setdefault to make a default empty dictionary and put it into out_groups if we haven't seen that target count yet.

If you had to handle the case of duplicate partials, you could replace the setdefault line with

out_groups.setdefault(target, []).append((partial, parent))

which would turn the group members into lists of tuples instead of dictionaries:

{1: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (7, 'f')],
2: [(5, 'a'), (6, 'd'), (8, 'c')],
3: [(9, 'c'), (10, 'a')]}

Python Split Dictionary into Smaller Dictionaries by Threshold Value

First of all, what you are describing here is very close to (or is ?) the Multiple knapsack problem. There are a numerous way to solve this problem, depending on what conditions you impose on the results.

I recommended you read this page and the resources associated with it to better frame your desired output. For example, can we omit items ? What if we cannot satisfy your constraint on the results (within [195,205]) with the current list of items ?

Using pure python, a naive approach to reduce code amount using a greedy approach could be (given that your dictionary is sorted in descending order):

# Initialize a list of dictionaries to fill
dicts = [{},{},{}]
# Define a counter
i = 0
# Define your maximum value
max_value = 205


for k,v in dict_sports.items():
for i in range(len(dicts)):
if sum(dicts[i].values()) + v < max_value:
dicts[i].update({k:v})
break
i+=1

for d in dicts:
print("---- {} ----".format(sum(d.values())))
print(d)

Giving

---- 203 ----
{'Skateboarding': 163, 'Baseball': 30, 'Skiing': 10}
---- 199 ----
{'Bowling': 134, 'Wrestling': 57, 'Boxing': 8}
---- 198 ----
{'Rugby': 83, 'Badminton': 24, 'Volleyball': 22, 'Basketball': 18, 'Football': 16, 'Weightlifting': 15, 'Golf': 14, 'Cricket': 6}

Note that this solution may skip items if the sum condition is not met for all dictionary.

How to split a python dictionary into multiple dictionaries based on values

Here is a general approach using a nested collections.defaultdict:

def categorize_dicts(dictionary):
dfd = defaultdict(defaultdict)
for k, v in d.items():
for i,j in zip(v, v[1:]):
dfd[j-i].setdefault(k,[]).extend((i, j))
return dfd

Demo:

In [28]: d = {'A': [0, 2, 5],
...: 'B': [1],
...: 'C': [3, 6, 9],
...: 'D': [4, 7, 10],
...: 'E': [8, 11, 13],
...: 'F': [12, 15, 17],
...: 'T': [19]}
...:

In [29]: categorize_dicts(d)
Out[29]:
defaultdict(collections.defaultdict,
{2: defaultdict(None, {'A': [0, 2], 'E': [11, 13], 'F': [15, 17]}),
3: defaultdict(None,
{'A': [2, 5],
'C': [3, 6, 6, 9],
'D': [4, 7, 7, 10],
'E': [8, 11],
'F': [12, 15]})})

Dynamically split a dictionary into multiple dictionaries in python3.6 depending on input provided

This code handles any keys starting with letters and ending in a number, which can contain any number of digits. If a key is found that doesn't end in a number it prints an error message, a proper program should do better error handling.

It saves each resulting dictionary into a dictionary sub_dicts, so it doesn't need to sort the input data.

import re

# Make a regex that finds the number
pat = re.compile(r'\d+')

my_dict = {
'name1': 'abc', 'job1': 'xyz', 'pos1': 'tak', 'phone1': 12345,
'name2': 'pqr', 'job2': 'ftr', 'pos2': 'lkj', 'phone2': 27654,
'name3': 'swq', 'job3': 'nme', 'pos3': 'mnb', 'phone3': 98421,
'bad': 'bad_data',
}

# Separate the data based on the trailing number of each key.
sub_dicts = {}
for k, v in my_dict.items():
m = pat.search(k)
if m:
num = m.group()
sub_dicts.setdefault(num, {})[k] = v
else:
print('Invalid key:', k, v)

for k in sub_dicts.keys():
print(sub_dicts[k])

output

Invalid key: bad bad_data
{'name1': 'abc', 'job1': 'xyz', 'pos1': 'tak', 'phone1': 12345}
{'name2': 'pqr', 'job2': 'ftr', 'pos2': 'lkj', 'phone2': 27654}
{'name3': 'swq', 'job3': 'nme', 'pos3': 'mnb', 'phone3': 98421}

(Python) Split dictionary in two based on a property

One line solution (with lower_excluded_users which I couldn't resist making)

included, excluded = dict(), dict()

# ssly, you don't have to do this everytime
lower_excluded_users = [x.lower() for x in EXCLUDED_USERS]

# and now the one-line answer using if-else-for construct with
# v substituted by D[k]. And instead of using `for k, v in dicn.items()`
# I have used [... for aKey in dicn.keys()]

[ excluded.update({aKey: users[aKey]}) \
if any(x in users[aKey]["name"].lower() for x in lower_excluded_users) \
else \
included.update({aKey: users[aKey]}) \
for aKey in users.keys()
]

Or one without beautification:

[excluded.update({aKey: users[aKey]}) if any(x in users[aKey]["name"].lower() for x in lower_excluded_users) else included.update({aKey: users[aKey]}) for aKey in users.keys()]

Split dictionary based on a value

Just do something like

key = 378.2
dd = {517.1: 'h', 182.8:'o', 306.5:'l', 378.2:'a'}
d1 = {k:dd[k] for k in dd if k < key}
d2 = {k:dd[k] for k in dd if k > key}

How to split dictionary according to key and value into multiple dictionaries using indexes?

You can put your for loop in dictionary comprehension:

selected_stalls = []
Day_of_week = 'Mon'
time_of_meal = 'None'

raw_list_stallinfo = {'MiniWok_Stall_Menu1': 'Monday_Tuesday@Wednesday', 'Item1: Seafood HorFun@MiniWok_Stall_Menu1': '$4.50', 'Item2: Fish HorFun@MiniWok_Stall_Menu1': '$3.50', 'Item3: Chicken Horfun@MiniWok_Stall_Menu1': '$3.50', 'remark:@MiniWok_Stall_Menu1': 'None', 'MiniWok_Stall_Menu2': 'Thursday_Friday@Sunday', 'Item1: Seafood Fried Rice@MiniWok_Stall_Menu2': '$4.50', 'Item2: Salted Fish Fried Rice@MiniWok_Stall_Menu2': '$3.50', 'Item3: Chicken Fried Rice@menu2': '$3.50', 'remark:@MiniWok_Stall_Menu2': 'None', 'MiniWok_Stall_Menu3': 'Monday_Tuesday_Wednesday_Thursday_Friday@Sunday', 'Item1: Chicken Porridge@MiniWok_Stall_Menu3': '$3.00', 'Item2: Century-egg porridge@MiniWok_Stall_Menu3': '$4.00', 'remark:@MiniWok_Stall_Menu3': 'Breakfast Only'}

raw_list = {raw_list_idx: raw_list_key for raw_list_idx, raw_list_key in enumerate(raw_list_stallinfo.keys()) if Day_of_week in raw_list_stallinfo[raw_list_key]}
selected_stalls.append(raw_list)
print(selected_stalls)

This will give the output:

[{0: 'MiniWok_Stall_Menu1', 10: 'MiniWok_Stall_Menu3'}]

To find the time_of_meal location:

location = {i: k for i, k in enumerate(raw_list_stallinfo.values()) if k == time_of_meal}
print(location)

Which gives the locations as:

{4: 'None', 9: 'None'}

Then to find the remark without hard-coding you can marry it up with the location above:

remark_location = {i: k for i, k in raw_list_stallinfo.items() if k == time_of_meal}
print(remark_location)

Which returns the full Key and Value:

{'remark:@MiniWok_Stall_Menu1': 'None', 'remark:@MiniWok_Stall_Menu2': 'None'}


Related Topics



Leave a reply



Submit