【C#】【Demo】生成编号算法

using PetsMall.Common;
using PetsMall.Model.Entites;
using System;
using System.Collections.Generic;
using System.Linq;

namespace CommonUtil
{
    /// <summary>
    /// 生成编号
    /// 编号模拟数字进制规则,可以用一个数字序号表示,字符在字符数组中下标表示数值,如编号“0”等于序号0,如字符集Sort中编号“A”等于序号9。
    /// 编号转为常见进制的序号,表示的数值可能非常大,无法计算。固用int数组内每个数值表示每个字符在字符数组下标,来转换数字和字符。
    /// 可用构造参数设置初始编号,序号将从初始编号开始,即初始编号等于序号0;
    /// 
    /// 例如ReportNumberSort为自增
    ///  testItem.ReportNumber = "";
    ///  db.Set<Order_TestItem>().Add(testItem);
    ///  db.SaveChanges();
    ///  testItem.ReportNumber = NumberCreateHelper.NotSort.No_SortToNumberString(testItem.ReportNumberSort);
    ///  db.SaveChanges();
    /// </summary>
    public class NumberCreateHelper
    {
        /// <summary>
        /// 生成编号显示字符,字符顺序
        /// </summary>
        public static readonly NumberCreateHelper Sort = new NumberCreateHelper(new char[] { '0', '1', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'X', 'Y', 'Z' }
        , ConfigurationHelper.AppSetting("NumberCreateHelper_InitNumber_Sort"));

        /// <summary>
        /// 生成编号显示字符,乱序
        /// </summary>
        public static readonly NumberCreateHelper NotSort = new NumberCreateHelper(new char[] { 'D', 'E', '0', '1', 'Q', 'C', 'F', 'G', '5', 'N', 'P', 'M', '6', 'R', 'X', '7', 'K', '8', 'S', 'T', '9', 'A', '3', '4', 'B', 'H', 'Y', 'Z' }
        , ConfigurationHelper.AppSetting("NumberCreateHelper_InitNumber_NotSort"));

        readonly char[] NO_pattern;
        readonly List<char> NO_patternList;
        readonly string initNumber;
        readonly int[] initInts;

        private NumberCreateHelper() { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="_NO_pattern">使用字符集,字符集下标对应int数组的数值,与int数组转换</param>
        /// <param name="_initNumber">初始编号,使用序号取编号,将从初始编号开始,初始编号等于序号0</param>
        private NumberCreateHelper(char[] _NO_pattern, string _initNumber = "")
        {
            if (_NO_pattern != null)
            {
                NO_pattern = _NO_pattern;
            }
            NO_patternList = NO_pattern.ToList();

            if (string.IsNullOrWhiteSpace(_initNumber))
            {
                _initNumber = NO_pattern[0].ToString();
            }

            initNumber = _initNumber;
            initInts = NO_NumberStringToInts(initNumber);
        }

        #region 生成编号
        /// <summary>
        /// 生成编号
        /// </summary>
        /// <param name="len">编号位数</param>
        /// <param name="v">编号数值</param>
        /// <returns></returns>
        public string NO_CreateNumberString(int len, out int[] v)
        {
            //生成len个小于_pattern.Length的整数
            Random random = new Random(~unchecked((int)DateTime.Now.Ticks));
            v = new int[len];
            string nu = "";
            for (int i = 0; i < len; i++)
            {
                v[i] = random.Next(0, NO_pattern.Length);
                nu += NO_pattern[v[i]];
            }
            return nu;
        }

        /// <summary>
        /// 下一个编号
        /// </summary>
        /// <returns></returns>
        public string NO_NumberStringNext(string nu)
        {
            var v = NO_NumberStringToInts(nu);
            v = NO_IntsIncreaseOne(v);
            return NO_IntsToNumberString(v);
        }

        /// <summary>
        /// int数组转编号字符
        /// </summary>
        /// <param name="nu"></param>
        /// <returns></returns>
        public string NO_IntsToNumberString(int[] v)
        {
            string nu = "";
            for (int i = 0; i < v.Length; i++)
            {
                nu += NO_pattern[v[i]];
            }
            return nu;
        }
        /// <summary>
        /// 编号字符转int数组
        /// </summary>
        /// <param name="nu"></param>
        /// <returns></returns>
        public int[] NO_NumberStringToInts(string nu)
        {
            int[] v = new int[nu.Length];
            for (int i = 0; i < nu.Length; i++)
            {
                v[i] = NO_patternList.IndexOf(nu[i]);
            }
            return v;
        }

        /// <summary>
        /// int数组增加1
        /// </summary>
        /// <param name="v"></param>
        /// <param name="index">当前执行下标,初始请默认为null</param>
        /// <returns></returns>
        private int[] NO_IntsIncreaseOne(int[] v, int? index = null)
        {
            int i = index ?? v.Length - 1;
            if (i < 0)
            {
                //无法增加
                throw new Exception("CreateReportNumberLast 无法增加,超出模块支持数字界限");
                return null;
            }
            if (v[i] < NO_pattern.Length - 1)
            {
                v[i]++;
                return v;
            }
            else
            {
                v[i] = 0;
                return NO_IntsIncreaseOne(v, i - 1);
            }
        }

        /// <summary>
        /// int数组减少1
        /// </summary>
        /// <param name="v"></param>
        /// <param name="index">当前执行下标,初始请默认为null</param>
        /// <returns></returns>
        private int[] NO_IntsReduceOne(int[] v, int? index = null)
        {
            int i = index ?? v.Length - 1;
            if (i < 0)
            {
                //无法减少
                throw new Exception("CreateReportNumberLast 无法减少,模块不支持负数");
                return null;
            }

            if (v[i] > 0)
            {
                v[i]--;
                return v;
            }
            else
            {
                v[i] = 0;
                return NO_IntsReduceOne(v, i - 1);
            }
        }


        /// <summary>
        /// 数组相减得到序号
        /// </summary>
        /// <param name="left">数组减法左边</param>
        /// <param name="right">数组减法右边,被减去</param>
        /// <param name="index">当前执行以右侧开锁计算的下标,初始请默认为null</param>
        /// <param name="max">字符集长度表示数字数组长度,相当于进制上限</param>
        /// <returns></returns>
        private int No_IntsReduceInts(int[] left, int[] right, int? index = null, int max = 0)
        {
            //max类型进制位数,满max进1
            if (max <= 0)
            {
                max = NO_pattern.Length;
            }

            //首次计算,将数组位数对齐
            if (index == null)
            {

                var lList = left.ToList();
                int lIndex = lList.FindIndex(x => x > 0);
                if (lIndex > 0)
                {
                    //移除减数左边的0
                    lList.RemoveRange(0, lIndex);
                    left = lList.ToArray();
                }

                var rList = right.ToList();
                int rIndex = rList.FindIndex(x => x > 0);
                if (rIndex < 0)
                {
                    throw new Exception("CreateReportNumberLast 无法计算序号,被减编号数组为负");
                    ////减负数和0都不变
                    //return NO_IntsToInt(left);
                }
                else if (rIndex > 0)
                {
                    //移除被减数左边的0
                    rList.RemoveRange(0, rIndex);
                    right = rList.ToArray();
                }

                if (right.Length > left.Length)
                {
                    throw new Exception("CreateReportNumberLast 无法计算序号,被减编号数组长度大于原编号数组");
                    ////被减位数大于减数位数,不变
                    //return NO_IntsToInt(left);
                }

                index = right.Length - 1;
            }

            int i = index.Value;

            //计算数组相减
            if (left[right.Length - left.Length + i] >= right[i])
            {
                left[right.Length - left.Length + i] -= right[i];
                i--;
                if (i < 0)
                {
                    return NO_IntsToInt(left);
                }
                else
                {
                    return No_IntsReduceInts(left, right, i);
                }
            }
            else
            {
                //无高位可取
                if (right.Length - left.Length + i - 1 < 0)
                {
                    throw new Exception("CreateReportNumberLast 无法计算序号,被减编号数组数值大于原编号数组");
                }

                //取高位减,被取高位为0,则会为负1,下一次递归还会到这里继续取高位
                left[right.Length - left.Length + i - 1]--;

                //如果当前位的left被上一次取高位到负1,则会到这里变为max-1。
                left[right.Length - left.Length + i] += max;

                return No_IntsReduceInts(left, right, i);
            }
        }


        /// <summary>
        /// 顺序序号转数组
        /// 编号表示数字很大,int类型不够作为参数用此方法转换,需配合初始编号使用
        /// </summary>
        /// <param name="sort"></param>
        /// <returns></returns>
        public int[] NO_SortNoToInts(int sort, int minLen = 0, int max = 0)
        {
            //max类型进制位数,满max进1
            if (max <= 0)
            {
                max = NO_pattern.Length;
            }
            List<int> res = new List<int>();

            int now = sort;
            while (now > 0)
            {
                res.Add(now % max);//取余
                now = now / max;//偏移
            }

            //补充0,
            if (minLen > 0 && res.Count() < minLen)
            {
                int count = res.Count();
                for (int i = 0; i < minLen - count; i++)
                {
                    res.Add(0);
                }
            }

            res.Reverse();

            return res.ToArray();
        }

        /// <summary>
        /// 数组转顺序序号
        /// 编号表示数字很大,容易数字溢出,需配合初始编号使用
        /// </summary>
        /// <param name="ints"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        public int NO_IntsToInt(int[] ints, int max = 0)
        {
            if (max <= 0)
            {
                max = NO_pattern.Length;
            }
            int res = 0;//ints[ints.Length-1]
            for (int i = ints.Length - 1; i > 0; i--)
            {
                res += (ints[i] * (int)Math.Pow(max, (ints.Length - 1) - i));
            }
            if (res < 0)
            {
                throw new Exception("CreateReportNumberLast 无法转为序号,数组表示数值溢出");
            }
            return res;
        }

        /// <summary>
        /// 序号转编号
        /// </summary>
        /// <param name="sort"></param>
        /// <returns></returns>
        public string No_SortToNumberString(int sort)
        {
            int[] ints = new int[initInts.Length];
            initInts.CopyTo(ints, 0);
            if (sort > 0)
            {
                for (int i = 0; i < sort; i++)
                {
                    ints = NO_IntsIncreaseOne(ints);
                }
            }

            return NO_IntsToNumberString(ints);
        }

        /// <summary>
        /// 编号转序号
        /// </summary>
        /// <param name="sort"></param>
        /// <returns></returns>
        public int No_NumberStringToSort(string nu)
        {
            int[] ints = new int[initInts.Length];
            initInts.CopyTo(ints, 0);
            return No_IntsReduceInts(NO_NumberStringToInts(nu), ints);
        }
        #endregion
    }
}

 

posted @ 2022-01-11 19:31  lanofsky  阅读(65)  评论(0编辑  收藏  举报