这个是在做机票相关业务时遇到的问题。
机票订单会根据情况被拆为多单,每单在不同时间范围内对应不同的退票费。
因为订单退改是一起退改,所以提供给用户的是两个订单总的退票费。
这就需要对多个订单在不同时间段的退票费进行交叉求和。
本处为方便,以订单被拆为两单为例。
如下,订单被拆为两单,两单在不同时间段退票费分别如下
求所有时间段的退票费。
即,求出
0——3——5——8——9——10
各个区间的退票费。
算法如下:
定义一个退票费的类如下,用来表示一个区间的起始以及对应包含的退票费。
/// <summary>
/// 时间段对应退票费列表
/// </summary>
class RefundFeeRange
{
public RefundFeeRange(int st, int en, List<int> fl)
{
Start = st; End = en; Fees = fl;
}
//起始时间点
public int Start { get; set; }
//结束时间点
public int End { get; set; }
//时间段内退票费
public List<int> Fees { get; set; }
}
两个区间交叉的情况是很多的,但区间不交叉的情况只有两种,a在b前,或者b在a前。
判断区间交叉,只要把不交叉的情况进行非处理即可。
方法如下:
//判断两个时间段是否交叉
static bool IsTimeConflict(RefundFeeRange a, RefundFeeRange b)
{
return !( a.Start >= b.End || a.End <= b.Start );
}
求区间交叉后的值的方法如下:
根据所有区间起始点,取出不重复节点
根据这些节点,得出新的不交叉的区间
用这些新的区间分别和旧的各个区间进行交叉判断,如果交叉就把对应值放入列表
返回新的集合即可
具体代码如下:
/// <summary>
/// 由多个可能冲突的时间段对应退票费,算出不冲突的时间段的退票费集合
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
static List<RefundFeeRange> RefundFeeCaculate(List<RefundFeeRange> param)
{
//时间段对应退票费集合
var temps = new List<RefundFeeRange>();
//获得所有不重复的时间点集合
var timePointList = new List<int>();
param.ForEach(x =>
{
timePointList.Add(x.Start);
timePointList.Add(x.End);
});
timePointList = timePointList.OrderBy(x => x).Distinct().ToList();
//获得所有不冲突的时间段集合
for (int i = 0; i < timePointList.Count - 1; i++)
{
temps.Add(new RefundFeeRange(timePointList[i], timePointList[i + 1], new List<int>()));
}
//获得每个时间段内对应的不同航班的退票费
temps.ForEach(x =>
{
param.ForEach(y =>
{
if (IsTimeConflict(x, y))
{
x.Fees.AddRange(y.Fees);
}
});
});
return temps;
}
以前面的例子中的两个订单退票费数据为例计算
static void Main(string[] args)
{
var li = new List<RefundFeeRange>() {
new RefundFeeRange(0,5,new List<int>(){100}),
new RefundFeeRange(5,8,new List<int>(){200}),
new RefundFeeRange(8,10,new List<int>(){300}),
new RefundFeeRange(0,3,new List<int>(){150}),
new RefundFeeRange(3,9,new List<int>(){220}),
new RefundFeeRange(9,10,new List<int>(){330})
};
var temps = RefundFeeCaculate(li);
temps.ForEach(x =>
{
Console.WriteLine(String.Format("{0}------{1}--------{2} : {3}", x.Start, x.End, x.Fees.Sum(), string.Join(",", x.Fees)));
});
Console.ReadLine();
}
输出结果如下
对比实际,可以看出结果相符。