You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为含Animal元素的字符串列表自定义Sort()排序并修正数字排序问题

C#字符串列表按Animal分组+自然排序方案

核心需求实现

通过自定义IComparer<string>实现Sort()方法的定制排序,同时解决数字排序异常问题:

  • 保留非<Animal .../>及<Animal>标签的元素,按字符串默认顺序排在列表前端(可调整)
  • <Animal>容器标签置于所有Animal数据标签之前
  • Animal数据标签先按Group属性排序,同组内按Name做自然排序(解决Horse1、Horse10、Horse2的顺序问题)

自定义比较器代码

public class AnimalStringComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        // 标记元素类型
        bool isXAnimalData = x.TrimStart().StartsWith("<Animal Name=\"");
        bool isYAnimalData = y.TrimStart().StartsWith("<Animal Name=\"");
        bool isXAnimalContainer = x.Trim() == "<Animal>";
        bool isYAnimalContainer = y.Trim() == "<Animal>";

        // 普通元素之间的排序
        if (!isXAnimalData && !isXAnimalContainer && !isYAnimalData && !isYAnimalContainer)
        {
            return string.Compare(x, y, StringComparison.Ordinal);
        }

        // 普通元素优先排在Animal相关元素前
        if (!isXAnimalData && !isXAnimalContainer && (isYAnimalData || isYAnimalContainer))
            return -1;
        if ((isXAnimalData || isXAnimalContainer) && !isYAnimalData && !isYAnimalContainer)
            return 1;

        // Animal容器标签之间相等
        if (isXAnimalContainer && isYAnimalContainer)
            return 0;

        // 容器标签排在数据标签前
        if (isXAnimalContainer && isYAnimalData)
            return -1;
        if (isYAnimalContainer && isXAnimalData)
            return 1;

        // Animal数据标签按Group、Name自然排序
        var xGroup = ExtractAttribute(x, "Group");
        var yGroup = ExtractAttribute(y, "Group");
        int groupCompare = string.Compare(xGroup, yGroup, StringComparison.OrdinalIgnoreCase);
        if (groupCompare != 0)
            return groupCompare;

        var xName = ExtractAttribute(x, "Name");
        var yName = ExtractAttribute(y, "Name");
        return NaturalCompare(xName, yName);
    }

    // 提取XML属性值(简单实现,复杂场景建议用XElement解析)
    private string ExtractAttribute(string xml, string attrName)
    {
        int start = xml.IndexOf($"{attrName}=\"");
        if (start == -1) return string.Empty;
        start += $"{attrName}=\"".Length;
        int end = xml.IndexOf("\"", start);
        return end == -1 ? string.Empty : xml.Substring(start, end - start);
    }

    // 自然排序逻辑:区分字母与数字,按数值比较数字部分
    private int NaturalCompare(string a, string b)
    {
        if (string.IsNullOrEmpty(a)) return string.IsNullOrEmpty(b) ? 0 : -1;
        if (string.IsNullOrEmpty(b)) return 1;

        int aIdx = 0, bIdx = 0;
        while (aIdx < a.Length && bIdx < b.Length)
        {
            if (char.IsDigit(a[aIdx]) && char.IsDigit(b[bIdx]))
            {
                string aNum = GetNumberPart(a, ref aIdx);
                string bNum = GetNumberPart(b, ref bIdx);
                
                if (long.TryParse(aNum, out long aLong) && long.TryParse(bNum, out long bLong))
                {
                    long numDiff = aLong - bLong;
                    if (numDiff != 0) return numDiff > 0 ? 1 : -1;
                }
                else
                {
                    int strDiff = string.Compare(aNum, bNum, StringComparison.Ordinal);
                    if (strDiff != 0) return strDiff;
                }
            }
            else
            {
                int charDiff = char.ToLowerInvariant(a[aIdx]).CompareTo(char.ToLowerInvariant(b[bIdx]));
                if (charDiff != 0) return charDiff;
                aIdx++;
                bIdx++;
            }
        }
        return a.Length - b.Length;
    }

    // 提取连续数字段
    private string GetNumberPart(string s, ref int idx)
    {
        int start = idx;
        while (idx < s.Length && char.IsDigit(s[idx])) idx++;
        return s.Substring(start, idx - start);
    }
}

使用方式

直接将自定义比较器传入Sort()方法即可:

var somedata = new List<string> {
    "<some data>",
    "  <some data else>",
    "</some data>",
    "<Animal>",
    "  <Animal Name=\"Horse10\" Group=\"Equine\" Colour=\"Black\" />",
    "  <Animal Name=\"Horse2\" Group=\"Equine\" Colour=\"Brown\" />",
    "  <Animal Name=\"Lion\" Group=\"Feline\" Colour=\"Brown\" />",
    "  <Animal Name=\"Horse1\" Group=\"Equine\" Colour=\"White\" />",
    "</some other data>"
};

somedata.Sort(new AnimalStringComparer());

// 验证排序结果
foreach (var item in somedata)
{
    Console.WriteLine(item);
}

可调整项

  • 若需将非Animal元素排在列表末尾,只需交换普通元素与Animal元素比较时的返回值(把-1和1互换)
  • 如需区分Group的大小写,将StringComparison.OrdinalIgnoreCase改为StringComparison.Ordinal
  • 复杂XML场景下,建议替换ExtractAttribute方法为XElement.Parse(xml).Attribute(attrName)?.Value,避免字符串解析的局限性

内容的提问来源于stack exchange,提问作者orecchione bruno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 04:54:57