对14.1.2.3和14.10.1.2.3.4等章节内容进行分类

本文关键字:分类 | 更新日期: 2023-09-27 18:21:04

我有不同深度的不同章节。

因此存在14.1和14.4.2以及14.7.8.8.2,依此类推

按字母数字排序的14.10将出现在14.2之前。太糟糕了。它应该在14.9之后。

有没有一种简单的方法可以在不添加前导零的情况下对se进行排序?和林克在一起?

对14.1.2.3和14.10.1.2.3.4等章节内容进行分类

public class NumberedSectionComparer : IComparer<string>
{
  private int Compare(string[] x, string[]y)
  {
    if(x.Length > y.Length)
      return -Compare(y, x);//saves needing separate logic.
    for(int i = 0; i != x.Length; ++i)
    {
      int cmp = int.Parse(x[i]).CompareTo(int.Parse(y[i]));
      if(cmp != 0)
        return cmp;
    }
    return x.Length == y.Length ? 0 : -1;
  }
  public int Compare(string x, string y)
  {
    if(ReferenceEquals(x, y))//short-cut
      return 0;
    if(x == null)
      return -1;
    if(y == null)
      return 1;
    try
    {
      return Compare(x.Split('.'), y.Split('.'));
    }
    catch(FormatException)
    {
      throw new ArgumentException();
    }
  }
}

我现在就做了,需要一些测试:

using System;
using System.Collections.Generic;
using System.Linq;
namespace TestesConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] vers = new[]
                              {
                                  "14.10",
                                  "14.9",
                                  "14.10.1",
                              };

            var ordered = vers.OrderBy(x => x, new VersionComparer()).ToList();
        }
    }
    public class VersionComparer : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            string[] xs = x.Split('.');
            string[] ys = y.Split('.');
            int maxLoop = Math.Min(xs.Length, ys.Length);
            for (int i = 0; i < maxLoop; i++)
            {
                if(int.Parse(xs[i]) > int.Parse(ys[i]))
                {
                    return 1;
                }
                else if(int.Parse(xs[i]) < int.Parse(ys[i]))
                {
                    return -1;
                }
            }
            if(xs.Length > ys.Length)
            {
                return 1;
            }
            else if(xs.Length < ys.Length)
            {
                return -1;
            }
            return 0;
        }
    }
}
var headers = new List<string> {"14.1.2.3", "14.1", "14.9", "14.2.1", "14.4.2", "14.10.1.2.3.4", "14.7.8.8.2"};
    headers.Sort(new MySorter());

class MySorter : IComparer<string>
    {
    public int Compare(string x, string y)
    {
    IList<string> a = x.Split('.');
    IList<string> b = y.Split('.');
    int numToCompare = (a.Count < b.Count) ? a.Count : b.Count;
    for (int i = 0; i < numToCompare; i++)
    {
    if (a[i].Equals(b[i]))
    continue;
    int numa = Convert.ToInt32(a[i]);
    int numb = Convert.ToInt32(b[i]);
     return numa.CompareTo(numb);
    }
    return a.Count.CompareTo(b.Count);
    }
    }

使用IComparer有一个很大的缺点,就是经常重复相当昂贵的计算,所以我认为预先计算订单标准是个好主意:

using System;
using System.Collections.Generic;
using System.Linq;
namespace ChapterSort
{
    class Program
    {
        static void Main(string[] args)
        {
            String[] chapters=new String[] {"14.1","14.4.2","14.7.8.8.2","14.10","14.2","14.9","14.10.1.2.3.4","14.1.2.3" };  
            IEnumerable<String> newchapters=chapters.OrderBy(x => new ChapterNumerizer(x,256,8).NumericValue);
            foreach (String s in newchapters) Console.WriteLine(s);
        }
    }
    public class ChapterNumerizer
    {
        private long numval;
        public long NumericValue {get{return numval;}}
        public ChapterNumerizer (string chapter,int n, int m)
        {
            string[] c = chapter.Split('.');
            numval=0;
            int j=0;
           foreach (String cc in c)
           {
               numval=n*numval+int.Parse(cc);
               j++;
           }
           while (j<m)
           {
               numval*=n;
               j++;
           }
        }
    }
}

此解决方案更通用。

public class SequenceComparer<T> : IComparer<IEnumerable<T>> where T : IComparable<T>
{
    public int Compare(IEnumerable<T> x, IEnumerable<T> y)
    {
        IEnumerator<T> enx = x.GetEnumerator();
        IEnumerator<T> eny = y.GetEnumerator();
        do
        {
            bool endx = enx.MoveNext();
            bool endy = eny.MoveNext();
            if (!endx && !endy)
                return 0;
            if (!endx)
                return -1;
            if (!endy)
                return 1;
            var comp = enx.Current.CompareTo(eny.Current);
            if(comp != 0)
                return comp;
        } while (true);
    }
}

然后使用:

var sv = vers.Select(v => new { Key = v, Split = v.Split('.').Select(Int32.Parse) });
var ordered = sv.OrderBy(x => x.Split, new SequenceComparer<int>()).Select(x => x.Key);

作为一个小型LINQ一行:

List<string> chapters= new List<string>()
{
    "14.1",
    "14.4.2",
    "14.7.8.8.2",
    "14.10",
    "14.2"
};
chapters.OrderBy(c => Regex.Replace(c, "[0-9]+", match => match.Value.PadLeft(10, '0')));

与级别无关,但肯定不是最好的性能。。。

学分将https://stackoverflow.com/a/5093939/226278