Python 将dict的一部分与副本合并
我是Python的初学者,所以请耐心听我说 我有一个目录,看起来像:Python 将dict的一部分与副本合并,python,python-3.x,Python,Python 3.x,我是Python的初学者,所以请耐心听我说 我有一个目录,看起来像: list = [ { "name": "Bus 60", "direction": "City", "timeLeft": "1", "timeNext": "" }, { "name": "Bus 60", "direction": "City", "timeLeft": "3",
list = [
{
"name": "Bus 60",
"direction": "City",
"timeLeft": "1",
"timeNext": ""
},
{
"name": "Bus 60",
"direction": "City",
"timeLeft": "3",
"timeNext": ""
},
{
"name": "Bus 1",
"direction": "Some Place",
"timeLeft": "15",
"timeNext": ""
},
{
"name": "Bus 1",
"direction": "Some Place",
"timeLeft": "30",
"timeNext": ""
},
{
"name": "Bus 1",
"direction": "That other place",
"timeLeft": "5",
"timeNext": ""
},
]
我希望根据名称和方向将这两种情况合并,如下所示:
new_list = [
{
"name": "Bus 60",
"direction": "City",
"timeLeft": "1",
"timeNext": "3"
},
{
"name": "Bus 1",
"direction": "Some Place",
"timeLeft": "15",
"timeNext": "30"
},
{
"name": "Bus 1",
"direction": "That other place",
"timeLeft": "5",
"timeNext": ""
},
]
new_list = list(merge_busses(mylist))
我如何才能做到这一点,并了解它实际上是如何工作的?
我尝试过很多循环解决方案,但最终都会出现很多重复或错误的合并
编辑:每个名称和方向的副本不得超过一个
编辑2:这是我的完整方法:
@APP.route('/api/vasttrafik/departures', methods=['POST'])
def get_departures():
""" Departures """
APP.logger.info('get_departures():')
data = request.get_json()
id_number = data['id']
current_date = date.today().strftime('%Y-%m-%d')
current_time = datetime.now().strftime('%H:%M')
# time_span = data['']
access_token = request.headers['access_token']
url = 'https://api.vasttrafik.se/bin/rest.exe/v2/departureBoard?id='\
+ id_number + '&date=' + current_date + '&time=' + current_time +\
'&format=json&timeSpan=90&maxDeparturesPerLine=2&needJourneyDetail=0'
headers = {'Authorization': 'Bearer ' + access_token}
req = requests.get(url, headers=headers)
json = req.json()
departure_board = json['DepartureBoard']
if 'error' in departure_board:
raise NotFoundException('Did not find anything')
departures = departure_board['Departure']
def departures_model(item):
def get_key_value(key):
return item[key] if key in item else ''
is_live = 'rtTime' in item
if is_live:
current_time = get_key_value('rtTime')
current_date = get_key_value('rtDate')
else:
current_time = get_key_value('time')
current_date = get_key_value('date')
direction = get_key_value('direction')
via = ''
if 'via' in direction:
direction, via = direction.split('via')
time_departure = datetime.strptime(current_date + ' ' + current_time, '%Y-%m-%d %H:%M')
time_now = datetime.now()
diff = time_departure - time_now
if time_now >= time_departure:
minutes_left = 0
else:
minutes_left = math.floor(((diff).seconds) / 60)
clock_left = item['rtTime'] if is_live else item['time']
return dict({
'accessibility': get_key_value('accessibility'),
'bgColor': get_key_value('bgColor'),
'clockLeft': clock_left,
'clockNext': '',
'timeLeft': int(minutes_left),
'timeNext': '',
'direction': direction.strip(),
'via': 'via ' + via.strip() if via != '' else via,
'name': get_key_value('name'),
'sname': get_key_value('sname'),
'type': get_key_value('type'),
'time': get_key_value('time'),
'date': get_key_value('date'),
'journeyid': get_key_value('journeyid'),
'track': get_key_value('track'),
'fgColor': get_key_value('fgColor'),
'isLive': is_live,
'night': 'night' in item,
})
mapped_departures = list(map(departures_model, departures))
def key(bus):
return bus["name"], bus["direction"]
def merge_busses(ls):
for (name, direction), busses in groupby(ls, key):
busses = list(busses)
times = [bus["timeLeft"] for bus in busses]
yield {
**busses[0],
"timeLeft": min(times, key=int),
"timeNext": max(times, key=int),
}
merge_departures = list(merge_busses(mapped_departures))
return jsonify({
'departures': merge_departures,
})
编辑3:我刚刚发现为什么L3viathan&Patrick Artner的解决方案不起作用。只有在预先对公交车列表进行排序的情况下,它们才起作用。所以我猜groupby需要dict相邻。我的解决方案是:我们使用itertools.groupby按总线的名称-方向组合对总线进行分组,然后生成字典,其中timeLeft是这些总线中最小的分钟数,如果我们只看到一条总线,timeNext要么是一个空字符串,要么是这些总线中的最大分钟数
from itertools import groupby
def key(bus):
return bus["name"], bus["direction"]
def merge_busses(ls):
for (name, direction), busses in groupby(sorted(ls, key=key), key):
busses = list(busses)
times = [bus["timeLeft"] for bus in busses]
yield {
**busses[0],
"timeLeft": min(times, key=int),
"timeNext": "" if len(times) == 1 else max(times, key=int),
}
像这样使用它:
new_list = [
{
"name": "Bus 60",
"direction": "City",
"timeLeft": "1",
"timeNext": "3"
},
{
"name": "Bus 1",
"direction": "Some Place",
"timeLeft": "15",
"timeNext": "30"
},
{
"name": "Bus 1",
"direction": "That other place",
"timeLeft": "5",
"timeNext": ""
},
]
new_list = list(merge_busses(mylist))
以您的示例为例,这将产生:
[
{
"name": "Bus 60",
"direction": "City",
"timeLeft": "1",
"timeNext": "3"
},
{
"name": "Bus 1",
"direction": "Some Place",
"timeLeft": "15",
"timeNext": "30"
},
{
"name": "Bus 1",
"direction": "That other place",
"timeLeft": "5",
"timeNext": ""
}
]
这是我的解决方案:我们使用itertools.groupby按名称方向组合对总线进行分组,然后生成字典,其中timeLeft是这些总线中最小的分钟数,而timeNext是空字符串(如果我们只看到一条总线),或者是这些总线中最大的分钟数
from itertools import groupby
def key(bus):
return bus["name"], bus["direction"]
def merge_busses(ls):
for (name, direction), busses in groupby(sorted(ls, key=key), key):
busses = list(busses)
times = [bus["timeLeft"] for bus in busses]
yield {
**busses[0],
"timeLeft": min(times, key=int),
"timeNext": "" if len(times) == 1 else max(times, key=int),
}
像这样使用它:
new_list = [
{
"name": "Bus 60",
"direction": "City",
"timeLeft": "1",
"timeNext": "3"
},
{
"name": "Bus 1",
"direction": "Some Place",
"timeLeft": "15",
"timeNext": "30"
},
{
"name": "Bus 1",
"direction": "That other place",
"timeLeft": "5",
"timeNext": ""
},
]
new_list = list(merge_busses(mylist))
以您的示例为例,这将产生:
[
{
"name": "Bus 60",
"direction": "City",
"timeLeft": "1",
"timeNext": "3"
},
{
"name": "Bus 1",
"direction": "Some Place",
"timeLeft": "15",
"timeNext": "30"
},
{
"name": "Bus 1",
"direction": "That other place",
"timeLeft": "5",
"timeNext": ""
}
]
实现这一点的一种方法是按总线的名称和方向对所有总线进行分组。然后合并数据,确保较早的时间在“timeLeft”中,较晚的时间在“timeNext”中: Doku: 输出:
[{'name': 'Bus 60', 'direction': 'City', 'timeLeft': '1', 'timeNext': '3'},
{'name': 'Bus 21', 'direction': 'City', 'timeLeft': '5', 'timeNext': ''}]
您编辑的示例将导致:
[{'name': 'Bus 60', 'direction': 'City', 'timeLeft': '1', 'timeNext': '3'},
{'name': 'Bus 1', 'direction': 'Some Place', 'timeLeft': '15', 'timeNext': '30'},
{'name': 'Bus 1', 'direction': 'That other place', 'timeLeft': '5', 'timeNext': ''}]
实现这一点的一种方法是按总线的名称和方向对所有总线进行分组。然后合并数据,确保较早的时间在“timeLeft”中,较晚的时间在“timeNext”中: Doku: 输出:
[{'name': 'Bus 60', 'direction': 'City', 'timeLeft': '1', 'timeNext': '3'},
{'name': 'Bus 21', 'direction': 'City', 'timeLeft': '5', 'timeNext': ''}]
您编辑的示例将导致:
[{'name': 'Bus 60', 'direction': 'City', 'timeLeft': '1', 'timeNext': '3'},
{'name': 'Bus 1', 'direction': 'Some Place', 'timeLeft': '15', 'timeNext': '30'},
{'name': 'Bus 1', 'direction': 'That other place', 'timeLeft': '5', 'timeNext': ''}]
列表是否总是有两个元素和键?是的,它总是有这些键,但它可以有更多的dict。请提供一个有两个以上dict的示例,看看输出是什么样子,然后根据什么逻辑将3移动到另一个字段?使用dict UPDATE将列表始终有两个元素和这些键?是的,它将始终有这些键,但它可以有更多的dict。请提供一个包含两个以上dict的示例,以了解输出情况,那么根据什么逻辑将3移动到另一个字段?使用dictupdate@L3viathan我不太明白为什么我需要对它进行排序——分组可以在无序列表上工作——很好,组的键将确保在一个组中只有相同的总线。或者你的意思是完成后的输出顺序?我对此有与L3viathan的解决方案相同的问题。它不会合并我的公交车发车。不会,因为列表排序后,它现在可以工作了。你也可以在方法偏差模型中看到,所有DICT看起来都是一样的。这里我告诉过你:@PatrickArtner别担心,我真的认为groupby的实现就是这样的。不管怎么说,我很高兴它现在起作用了。谢谢你的帮助!剥离只是为了确保它不存在差异?@l3via然后我不太明白为什么我需要对它进行排序-分组在无序列表上工作很好,组的键将确保只有相同的总线在一个组中。或者你的意思是完成后的输出顺序?我对此有与L3viathan的解决方案相同的问题。它不会合并我的公交车发车。不会,因为列表排序后,它现在可以工作了。你也可以在方法偏差模型中看到,所有DICT看起来都是一样的。这里我告诉过你:@PatrickArtner别担心,我真的认为groupby的实现就是这样的。不管怎么说,我很高兴它现在起作用了。谢谢你的帮助!剥离只是为了确保它不存在差异?我没有通知您,我在dicts中还有其他需要的键/值。在您的第一个解决方案中,我可以使用**first[key]获取其他键,但在这个新解决方案中,我不确定如何执行该操作。bus未定义,因为它的作用域位于times变量内。我现在可以使用该代码获取重复项。我已经用文件中的全部内容更新了我的主要帖子。我没有收到你提供的例子的副本。给我一个更好的例子,我没有缩进来为这个设置一个烧瓶API。所以我是对的,你需要对它进行排序。已在编辑中修复。我未能通知您DICT中还有其他需要的键/值。在您的第一个解决方案中,我可以使用**first[key]获取其他键,但在这个新解决方案中,我不确定如何执行该操作。bus未定义,因为它的作用域位于times变量内。我现在可以使用该代码获取重复项。我已经用文件中的全部内容更新了我的主要帖子。我没有收到你提供的例子的副本。给我一个更好的例子,我不缩进来设置一个烧瓶API 您需要对其进行排序,这是正确的。在编辑中修复。