在C#中对List <String>进行排序

Tho*_*eld 16 c# natural-sort

如何根据项的整数值对List进行排序

清单就像

"1"
"5"
"3"
"6"
"11"
"9"
"NUM1"
"NUM0"
Run Code Online (Sandbox Code Playgroud)

结果应该是这样的

"1"
"3"
"5"
"6"
"9"
"11"
"NUM0"
"NUM1"
Run Code Online (Sandbox Code Playgroud)

有什么想法使用LINQ或Lambda表达式吗?

提前致谢

Mar*_*ell 16

怎么样:

    list.Sort((x, y) =>
    {
        int ix, iy;
        return int.TryParse(x, out ix) && int.TryParse(y, out iy)
              ? ix.CompareTo(iy) : string.Compare(x, y);
    });
Run Code Online (Sandbox Code Playgroud)

  • @Xander - 定义"明显"; 引用的问题是"整数值" - 但除非OP定义*应该*允许的术语/模式,否则我不会将"NUM10"作为整数值包含在内. (5认同)
  • 那么"NUM10"和"NUM2"的差异怎么样,对我们来说"NUM2"显然是在"NUM10"之前,但它不会那样排序 (4认同)

ang*_*son 16

这被称为"自然排序顺序",通常用于对您拥有的项目进行排序,如文件名等.

这是一个天真的(在某种意义上,它可能存在大量的unicode问题)实现似乎可以解决这个问题:

您可以将以下代码复制到LINQPad中以执行它并进行测试.

基本上比较算法将确定数字字符串内,并通过填充最短的一个具有前导零处理这些,所以比如两个字符串"Test123Abc",并"Test7X"应就好像它们是进行比较"Test123Abc""Test007X",这应该产生你想要什么.

然而,当我说"天真"时,我的意思是我可能在这里有很多真正的unicode问题,比如处理变音符号和多码点字符.如果有人能够提供更好的实施,我很乐意看到它.

笔记:

  • 实现实际上并没有解析数字,所以任意长数应该可以正常工作
  • 由于它实际上并没有将数字解析为"数字",因此浮点数将无法正确处理,"123.45"与"123.789"将被比较为"123.045"与"123.789",这是错误的.

码:

void Main()
{
    List<string> input = new List<string>
    {
        "1", "5", "3", "6", "11", "9", "A1", "A0"
    };
    var output = input.NaturalSort();
    output.Dump();
}

public static class Extensions
{
    public static IEnumerable<string> NaturalSort(
        this IEnumerable<string> collection)
    {
        return NaturalSort(collection, CultureInfo.CurrentCulture);
    }

    public static IEnumerable<string> NaturalSort(
        this IEnumerable<string> collection, CultureInfo cultureInfo)
    {
        return collection.OrderBy(s => s, new NaturalComparer(cultureInfo));
    }

    private class NaturalComparer : IComparer<string>
    {
        private readonly CultureInfo _CultureInfo;

        public NaturalComparer(CultureInfo cultureInfo)
        {
            _CultureInfo = cultureInfo;
        }

        public int Compare(string x, string y)
        {
            // simple cases
            if (x == y) // also handles null
                return 0;
            if (x == null)
                return -1;
            if (y == null)
                return +1;

            int ix = 0;
            int iy = 0;
            while (ix < x.Length && iy < y.Length)
            {
                if (Char.IsDigit(x[ix]) && Char.IsDigit(y[iy]))
                {
                    // We found numbers, so grab both numbers
                    int ix1 = ix++;
                    int iy1 = iy++;
                    while (ix < x.Length && Char.IsDigit(x[ix]))
                        ix++;
                    while (iy < y.Length && Char.IsDigit(y[iy]))
                        iy++;
                    string numberFromX = x.Substring(ix1, ix - ix1);
                    string numberFromY = y.Substring(iy1, iy - iy1);

                    // Pad them with 0's to have the same length
                    int maxLength = Math.Max(
                        numberFromX.Length,
                        numberFromY.Length);
                    numberFromX = numberFromX.PadLeft(maxLength, '0');
                    numberFromY = numberFromY.PadLeft(maxLength, '0');

                    int comparison = _CultureInfo
                        .CompareInfo.Compare(numberFromX, numberFromY);
                    if (comparison != 0)
                        return comparison;
                }
                else
                {
                    int comparison = _CultureInfo
                        .CompareInfo.Compare(x, ix, 1, y, iy, 1);
                    if (comparison != 0)
                        return comparison;
                    ix++;
                    iy++;
                }
            }

            // we should not be here with no parts left, they're equal
            Debug.Assert(ix < x.Length || iy < y.Length);

            // we still got parts of x left, y comes first
            if (ix < x.Length)
                return +1;

            // we still got parts of y left, x comes first
            return -1;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)