我有一个结果行块,并且我试图将它们分组为嵌套[{key: value[{key:value[]}]}]
的两个级别。顶级键上的值不唯一。
我一直在尝试使用defaultdict
,但由于存在非唯一性,所以在两个级别上都没有成功分组。遍历数据可能会更好,但我也没有成功。
开始数据:
data =
[{'Name': 'Bob', 'Time': 12, 'Place': 'Home'},
{'Name': 'Bob', 'Time': 11, 'Place': 'Home'},
{'Name': 'Jerry', 'Time': 5, 'Place': 'Home'},
{'Name': 'Jerry', 'Time': 11, 'Place': '-----'},
{'Name': 'Jerry', 'Time': 11, 'Place': 'Work'}]
最终所需数据:
[{"Name": "Bob", "Details":[{"Place":"Home", "Time":[12, 11]}]},
{"Name": "Jerry", "Details":[{"Place":"Home", "Time":[5]},
{"Place":"-----", "Time":[11]},
{"Place":"Work", "Time":[11]}]}]
答案 0 :(得分:2)
您可以使用Name
按Place
和itertools.groupby
分组,
>>> import itertools
>>> from collections import defaultdict
>>> data
[{'Name': 'Bob', 'Time': 12, 'Place': 'Home'}, {'Name': 'Bob', 'Time': 11, 'Place': 'Home'}, {'Name': 'Jerry', 'Time': 5, 'Place': 'Home'}, {'Name': 'Jerry', 'Time': 11, 'Place': '-----'}, {'Name': 'Jerry', 'Time': 11, 'Place': 'Work'}]
>>> sorted_data = sorted(data, key=lambda x: (x['Name'], x['Place'])) # sorting before grouping as suggested by @wwii, because The returned group is itself an iterator that shares the underlying iterable with groupby(). Please see (https://docs.python.org/3/library/itertools.html#itertools.groupby)
>>> d = defaultdict(list)
>>> y = itertools.groupby(sorted_data, lambda x: (x['Name'], x['Place']))
>>> for group, grouper in y:
... time_ = [item['Time'] for item in grouper]
... name, place = group
... d[name].append({'Place': place, 'Time': time_})
...
>>> d
defaultdict(<class 'list'>, {'Bob': [{'Place': 'Home', 'Time': [12, 11]}], 'Jerry': [{'Place': 'Home', 'Time': [5]}, {'Place': '-----', 'Time': [11]}, {'Place': 'Work', 'Time': [11]}]})
>>> pprint.pprint(dict(d))
{'Bob': [{'Place': 'Home', 'Time': [12, 11]}],
'Jerry': [{'Place': 'Home', 'Time': [5]},
{'Place': '-----', 'Time': [11]},
{'Place': 'Work', 'Time': [11]}]}
如果您需要显示的确切结构,
>>> f_data = []
>>> for key, value in d.items():
... f_data.append({'Name': key, 'Details': value})
...
>>> pprint.pprint(f_data)
[{'Details': [{'Place': 'Home', 'Time': [12, 11]}], 'Name': 'Bob'},
{'Details': [{'Place': '-----', 'Time': [11]},
{'Place': 'Home', 'Time': [5]},
{'Place': 'Work', 'Time': [11]}],
'Name': 'Jerry'}]
答案 1 :(得分:2)
排序数据;按'Name'
分组,按'Place'
分组结果;提取时间。
import operator
name = operator.itemgetter('Name')
where = operator.itemgetter('Place')
time = operator.itemgetter('Time')
data.sort(key=lambda x: (name(x),where(x)))
result = []
for name, group in itertools.groupby(data,key=name):
d = {'Name':name, 'Details':[]}
for place, times in itertools.groupby(group,key=where):
times = map(time, times)
d['Details'].append({'Place':place, 'Time':list(times)})
result.append(d)
我喜欢使用operator.itemgetter
而不是lambda函数,如果它将多次使用。只是我个人的喜好。
答案 2 :(得分:0)
我试图在熊猫的帮助下解决它。看看:
import pandas as pd
data = [{'Name': 'Bob', 'Time': 12, 'Place': 'Home'},
{'Name': 'Bob', 'Time': 11, 'Place': 'Home'},
{'Name': 'Jerry', 'Time': 5, 'Place': 'Home'},
{'Name': 'Jerry', 'Time': 11, 'Place': '-----'},
{'Name': 'Jerry', 'Time': 11, 'Place': 'Work'}]
df = pd.DataFrame.from_dict(data)
#Take the unique names only
names = df["Name"].unique()
#This list will hold the desired values
new_list = []
# Iterate over names
for n in names:
# Make subset off the data set where name is n
subset = df[df["Name"]==n]
# Get Unique Places in the subset
places = subset["Place"].unique()
# This will hold the details
details = []
# Iterate over unique places
for p in places:
# Get times from subset where place is and convert to list
times = subset[subset["Place"]==p]["Time"].tolist()
# Append to details list
details.append({"Place":p,"Time":times})
# Add the details in new_list as the format you preferred
new_list.append({"Name":n, "Details":details})
print(new_list)
答案 3 :(得分:0)
通过defaultdict
加上迭代,您已经有了正确的想法。唯一有点棘手的地方是嵌套defaultdict
。
from collections import defaultdict
def timegroup(data):
grouped = defaultdict(lambda:defaultdict(list))
for d in data:
grouped[d['Name']][d['Place']].append(d['Time'])
for name, details in grouped.items():
yield {'Name': name,
'Details': [{'Place': p, 'Time': t} for p, t in details.items()]}
(我喜欢将生成器用于此类操作,因为有时您只想迭代结果,在这种情况下,您不需要列表,如果需要列表,则很容易创建一个列表。)