在TMS模块,对同去向不同客户之间的订单进行拼车以节省运输成本。
使用Python的interval、itertools 进行拼车。
# -*- codeing = utf-8 -*-
# @File : TMS拼车2.py
# @Author : 一起种梧桐吧
# @Version : Python 3.10.0
# @Software : PyCharm
# @Time : 2023年7月31日
# @Purpose : TMS运输管理系统同路线客户拼车
from interval import Interval
from itertools import combinations
XL = ["东", "西", "南", "北"]
KH = {"客户01": ["东", 100],
"客户02": ["东", 150],
"客户03": ["东", 190],
"客户04": ["东", 250],
"客户05": ["南", 160],
"客户06": ["南", 170],
"客户07": ["南", 200]}
ZZ = {"客户01": {"dd01": 12550, "dd02": 300},
"客户02": {"dd03": 11020, "dd04": 11000, "dd05": 1180, },
"客户03": {"dd06": 11050, "dd07": 1220, "dd08": 110, },
"客户04": {"dd09": 6350, "dd10": 5280},
"客户05": {"dd11": 3050, "dd12": 3180},
"客户06": {"dd13": 3520, "dd14": 3180},
"客户07": {"dd15": 5390, "dd16": 3210}}
CL = {"X": 11500, "D": 13500}
def load_1shop1order(shop: str, zzl_min: float, zzl_max: float):
'''
单门店-单订单装车
:param zzl_min: 最小载重量
:param zzl_max: 最大载重量
:return: 满足条件的订单ID
'''
zzl_interval = Interval(zzl_min, zzl_max)
for item in sorted(ZZ[shop].items(), key=lambda x: x[1], reverse=True):
if item[1] in zzl_interval:
return item[0], item[1]
elif item[1] < zzl_min:
return None
else:
continue
else:
return None
def load_1shop2order(shop: str, zzl_min: float, zzl_max: float):
'''
单门店-多订单装车
:param zzl_min: 最小载重量
:param zzl_max: 最大载重量
:return: 满足条件的订单ID
'''
zzl_interval = Interval(zzl_min, zzl_max)
dct_order = ZZ[shop]
if sum(dct_order.values()) in zzl_interval:
return tuple(dct_order.keys()), sum(dct_order.values())
elif sum(dct_order.values()) <= zzl_min:
return None
else:
lst_order = []
for key, value in dct_order.items():
if value <= zzl_max:
lst_order.append(key)
lst_comb = []
for i in range(1, len(lst_order) + 1):
lst_comb.extend(combinations(lst_order, i))
dct_comb = {}
for order_comb in lst_comb:
zl_order_comb = 0
for order in order_comb:
zl_order_comb += dct_order[order]
if zl_order_comb in zzl_interval:
dct_comb.update({order_comb: zl_order_comb})
for item in sorted(dct_comb.items(), key=lambda x: x[1], reverse=True):
if item[1] in zzl_interval:
return item[0], item[1]
elif item[1] < zzl_min:
return None
else:
continue
else:
return None
def load(truck=CL):
'''
根据卡车装载量进行自动装载
:param truck: 卡车信息
:return: 满足条件的订单ID
'''
zzl_min = truck["X"]
zzl_max = truck["D"]
zzl_interval = Interval(zzl_min, zzl_max)
dct_order = {}
for item in ZZ.values():
dct_order.update(item)
# step_01:尝试单店单订单装载
lst_order1 = []
for shop in ZZ.keys():
res = load_1shop1order(shop, zzl_min, zzl_max)
if res:
lst_order1.append(res)
# print(lst_order1)
dct_order_load1 = {}
for item_comb in lst_order1:
if item_comb:
dct_order_load1.update({item_comb[0]: item_comb[1]})
if dct_order_load1:
for key, value in sorted(dct_order_load1.items(), key=lambda x: x[1], reverse=True):
# return key, value
print("step_01", key, value)
# step_02:尝试单店多订单装载
lst_order2 = []
for shop in ZZ.keys():
res = load_1shop2order(shop, zzl_min, zzl_max)
if res:
lst_order2.append(res)
# print(lst_order2)
dct_order_load2 = {}
for item_comb in lst_order2:
if item_comb:
dct_order_load2.update({item_comb[0]: item_comb[1]})
if dct_order_load2:
for key, value in sorted(dct_order_load2.items(), key=lambda x: x[1], reverse=True):
# return key, value
print("step_02", key, value)
# step_03:尝试2店拼订单装载(由远及近)
dct_shop_03 = {}
zzl_interval_03 = Interval(zzl_min * 0.5, zzl_max * 0.75)
for shop in ZZ.keys():
zzl_shop = sum(ZZ[shop].values())
if zzl_shop in zzl_interval_03:
dct_shop_03[shop] = zzl_shop
for key03, value03 in sorted(dct_shop_03.items(), key=lambda x: x[1], reverse=True):
zzl_interval_new_03 = Interval(value03 * 0.33, value03) & Interval(zzl_min - value03, zzl_max - value03)
if not zzl_interval_new_03:
continue
[qx03, yj03] = KH[key03]
lst_shop_03_02 = []
for shop03_02, qxyj03_02 in KH.items():
if (qxyj03_02[0] == qx03) & (yj03 - qxyj03_02[1] in Interval(0, 50, lower_closed=False)):
lst_shop_03_02.append(shop03_02)
if not lst_shop_03_02:
continue
else:
lst_order03 = []
for shop02 in lst_shop_03_02:
res = load_1shop2order(shop02, zzl_interval_new_03.lower_bound, zzl_interval_new_03.upper_bound)
if res:
lst_order03.append(res)
if not res:
continue
dct_order_load03 = {}
for item_comb in lst_order03:
if item_comb:
dct_order_load03.update({item_comb[0]: item_comb[1]})
if dct_order_load03:
for key03_02, value03_02 in sorted(dct_order_load03.items(), key=lambda x: x[1], reverse=True):
lst_order_shop = list(ZZ[key03].keys())
for order in key03_02:
lst_order_shop.append(order)
# return key, value
print("step_03", tuple(lst_order_shop), value03_02 + value03)
# step_04:尝试2店拼订单装载(由近到远)
dct_shop_04 = {}
zzl_interval_04 = Interval(zzl_min * 0.25, zzl_max * 0.5)
for shop in ZZ.keys():
zzl_shop = sum(ZZ[shop].values())
if zzl_shop in zzl_interval_04:
dct_shop_04[shop] = zzl_shop
for key04, value04 in sorted(dct_shop_04.items(), key=lambda x: x[1], reverse=True):
# print(Interval(value * 0.33, value), Interval(zzl_min - value, zzl_max - value))
zzl_interval_new_04 = Interval(value04, value04 * 3) & Interval(zzl_min - value04, zzl_max - value04)
if not zzl_interval_new_04:
continue
[qx04, yj04] = KH[key04]
lst_shop_04 = []
for shop04_02, qxyj04_02 in KH.items():
if (qxyj04_02[0] == qx04) & (qxyj04_02[1] - yj04 in Interval(0, 50, lower_closed=False)):
lst_shop_04.append(shop04_02)
if not lst_shop_04:
continue
else:
lst_order04 = []
for shop04_02 in lst_shop_04:
res = load_1shop2order(shop04_02, zzl_interval_new_04.lower_bound, zzl_interval_new_04.upper_bound)
if res:
lst_order04.append(res)
# print(lst_order04)
dct_order_load04 = {}
for item_comb in lst_order04:
if item_comb:
dct_order_load04.update({item_comb[0]: item_comb[1]})
if dct_order_load04:
for key04_02, value04_02 in sorted(dct_order_load04.items(), key=lambda x: x[1], reverse=True):
lst_order_shop = list(ZZ[key04].keys())
for order in key04_02:
lst_order_shop.append(order)
# return key, value
print("step_04", tuple(lst_order_shop), value04_02 + value04)
if __name__ == "__main__":
load()