• 拆单情况下,多个订单在不同时间段的总退票费计算——区间交叉计算的通用算法


    这个是在做机票相关业务时遇到的问题。

    机票订单会根据情况被拆为多单,每单在不同时间范围内对应不同的退票费。

    因为订单退改是一起退改,所以提供给用户的是两个订单总的退票费。

    这就需要对多个订单在不同时间段的退票费进行交叉求和。

    本处为方便,以订单被拆为两单为例。

    如下,订单被拆为两单,两单在不同时间段退票费分别如下

     

    求所有时间段的退票费。

    即,求出

    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();
            }

    输出结果如下

     

    对比实际,可以看出结果相符。

  • 相关阅读:
    webpack打包时候去掉console.log配置
    nodejs 同时create多条数据到接口中
    element ui 对话框eldialog关闭事件
    elementui 禁用radio
    git 更改远程地址
    js 快速排序
    vue $set $nextTick()
    js includes()
    人工智能导论 第四章答案 (部分)
    大促来临,你的数据库系统准备好了吗?
  • 原文地址:https://www.cnblogs.com/yuwen/p/10318542.html
Copyright © 2020-2023  润新知