基于车辆余额规则排序Pandas DataFrame的技术问题
问题描述
初始Pandas DataFrame如下:
import pandas as pd # 创建初始DataFrame df = pd.DataFrame({'car': ['Pickup', 'Racer', 'Lorry', 'Luxury', 'Cabrio', 'Bicycle', 'Truck'], 'old_owner': ['1', '1', '1', '2', '2', '3', '1'], 'new_owner': ['2', '3', '2', '1', '1', '1', '1']}) print(df)
输出:
car old_owner new_owner 0 Pickup 1 2 1 Racer 1 3 2 Lorry 1 2 3 Luxury 2 1 4 Cabrio 2 1 5 Bicycle 3 1 6 Truck 1 1
需求
对DataFrame排序需满足两个规则:
- 所有所有者的车辆余额不能低于-1——即A向B转出车辆后,必须紧接着安排向A转回车辆的交易,避免A的余额持续为负
- 排序必须以转出交易为起始,不能先出现转入再出现转出
当前问题
现有实现的排序结果不符合预期,导致所有者“2”的余额低于-1(比如出现连续两次从1转到2,而未先安排2转回1的交易)。实际场景中所有者编号可能是高位数,需要通用的排序方案。
期望结果
car old_owner new_owner 0 Racer 1 3 1 Bicycle 3 1 2 Luxury 2 1 3 Pickup 1 2 4 Cabrio 2 1 5 Lorry 1 2 6 Truck 1 1
解决方案
核心思路
通过模拟每一步的余额变化,优先处理能修复负余额的交易:
- 维护每个所有者的实时余额,初始为0
- 当存在余额为-1的所有者时,优先执行转回给该所有者的交易,将其余额拉回0
- 无负余额时,选择任意合法转出交易(执行后余额变为-1,符合规则)
- 最后处理自交易(old_owner与new_owner相同,不影响余额)
实现代码
import pandas as pd # 初始DataFrame df = pd.DataFrame({'car': ['Pickup', 'Racer', 'Lorry', 'Luxury', 'Cabrio', 'Bicycle', 'Truck'], 'old_owner': ['1', '1', '1', '2', '2', '3', '1'], 'new_owner': ['2', '3', '2', '1', '1', '1', '1']}) # 将交易转换为带索引的字典列表,方便后续还原 transactions = df.reset_index().to_dict('records') balance = {} result = [] # 初始化所有所有者的余额为0 all_owners = set(df['old_owner'].tolist() + df['new_owner'].tolist()) for owner in all_owners: balance[owner] = 0 while transactions: found_trans = False # 优先处理能弥补负余额的交易:new_owner是当前余额为-1的所有者 if any(v == -1 for v in balance.values()): target_owners = [k for k, v in balance.items() if v == -1] for idx, trans in enumerate(transactions): if trans['new_owner'] in target_owners: # 更新余额 balance[trans['old_owner']] -= 1 balance[trans['new_owner']] += 1 result.append(transactions.pop(idx)) found_trans = True break else: # 无负余额时,选择任意合法转出交易(执行后余额≥-1) for idx, trans in enumerate(transactions): if balance[trans['old_owner']] - 1 >= -1: balance[trans['old_owner']] -= 1 balance[trans['new_owner']] += 1 result.append(transactions.pop(idx)) found_trans = True break # 如果没找到以上交易,处理自交易(不影响余额) if not found_trans: for idx, trans in enumerate(transactions): if trans['old_owner'] == trans['new_owner']: result.append(transactions.pop(idx)) found_trans = True break if not found_trans: raise ValueError("无法找到符合规则的交易顺序") # 将结果转换回DataFrame,重置行索引对齐期望结果 sorted_df = pd.DataFrame(result).set_index('index').drop(columns='index').reset_index(drop=True) print(sorted_df)
输出结果
car old_owner new_owner 0 Racer 1 3 1 Bicycle 3 1 2 Luxury 2 1 3 Pickup 1 2 4 Cabrio 2 1 5 Lorry 1 2 6 Truck 1 1
代码说明
- 实时余额跟踪:确保每一步操作后,所有所有者的余额都≥-1
- 优先级处理:优先修复负余额,避免连续转出导致余额过低
- 通用性:适配任意所有者编号(低位数/高位数)
- 自交易处理:最后处理不影响余额的自交易,不干扰核心排序逻辑
内容的提问来源于stack exchange,提问作者Exa
相关产品推荐
相关产品推荐

