Skip to main content
 首页 » 编程设计

python之将字典的一部分与副本合并

2025年05月04日16shihaiming

我是 Python 的初学者,所以请多多包涵。

我有一个看起来像这样的字典列表:

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": "" 
    }, 
] 

我如何才能实现这一目标并了解它的实际工作原理? 我尝试了很多带有循环的解决方案,但它们最终都以大量重复或错误合并告终。

编辑:每个名称和方向的重复项永远不会超过一个。

编辑 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 需要相邻的字典。

请您参考如下方法:

这是我的解决方案:我们使用 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 = 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": "" 
    } 
]