C# 按数字顺序排列字母数字字符串,然后按前缀/后缀排序

C# 按数字顺序排列字母数字字符串,然后按前缀/后缀排序,c#,.net,linq,sorting,C#,.net,Linq,Sorting,我有一个复杂的排序模式要复制,我的解决方案似乎有点笨拙。 我的输入是一个数字列表,可以有几个字母作为后缀和前缀,它们都是唯一的字母(“aaa”、“aab”、“ac”等)。 我需要按数字排序,然后按后缀排序(如果有),然后按前缀排序(如果有) 例如 将被分类为 1 a1a 1b 2 a2b 3 5aa 5ab 5ac 11 aba11ca abb11ca 12 下面是我使用Linq提出的解决方案 static void Main(string[] args) { var arr = ne

我有一个复杂的排序模式要复制,我的解决方案似乎有点笨拙。 我的输入是一个数字列表,可以有几个字母作为后缀和前缀,它们都是唯一的字母(“aaa”、“aab”、“ac”等)。 我需要按数字排序,然后按后缀排序(如果有),然后按前缀排序(如果有)

例如

将被分类为

1
a1a
1b
2
a2b
3
5aa
5ab
5ac
11
aba11ca
abb11ca
12
下面是我使用Linq提出的解决方案

static void Main(string[] args)
{
    var arr = new []
    {"b2","a1a","5ac","1","12","2","11","5aa","3","5ab","a1","a2b","abb11ca","1b","aba11ca"
    };
    var ordered = arr.Select(str => {
                var parts = SplitIntoPrefixNumberSuffix(str);
                var number = int.Parse(parts[1]);
                return new { str, parts, number };
            })
            .OrderBy(x => x.number).ThenBy(x => x.parts[2]).ThenBy(x => x.parts[0])
            .Select(x => x.str);

    Console.WriteLine("sorted array: ");
    foreach (var s in ordered)
    {
        Console.WriteLine("{0}", s);
    }

    Console.ReadLine();
}      

public static string[] SplitIntoPrefixNumberSuffix(string str)
{
    var numChar = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
    var numLoc = str.IndexOfAny(numChar);
    var nums = "";
    foreach (var c in str)
    {
        if (char.IsDigit(c))
            nums = nums + c;
    }
    Console.WriteLine("numLoc: {0}; nums: {1}", numLoc, nums.Count());
    var prefix = str.Substring(0, numLoc);
    var suffix = str.Substring(numLoc + nums.Count());
    Console.WriteLine("prefix {0}; nums {1}; suffix {2}", prefix, nums, suffix);
    return new[] { prefix, nums, suffix };
}
这里有一个.netfiddle正在工作:

虽然有效,但感觉这不是一个很好的解决方案。我对集合进行了多次迭代,我想我应该使用一个自定义的可比较的

我以前从未写过类似的作品;我看了它,并可以遵循它,但还不够好,修改它,以适应我的需要


是否有一个IComparable我可以用来做上述工作?关于学习如何编写一个字符串的好地方有什么建议吗?

因此,您可以使用正则表达式命名的组来拆分字符串的各个组成部分,然后按每个组成部分排序:

var regex = new Regex(@"^(?<pre>\D*)(?<num>\d+)(?<suff>\D*)$");
var ordered = data.Select(d => (match: regex.Match(d), value: d))
    .Where(x => x.match.Success) //throw away anything that doesn't conform
    .Select(x => (
        x.value, 
        pre: x.match.Groups["pre"].Value, 
        num: int.Parse(x.match.Groups["num"].Value), 
        suff: x.match.Groups["suff"].Value))
    .OrderBy(x => x.num)
    .ThenBy(x => x.suff)
    .ThenBy(x => x.pre)
    .Select(x => x.value);

因此,您可以使用正则表达式命名组拆分字符串的各个组件,然后按每个组件排序:

var regex = new Regex(@"^(?<pre>\D*)(?<num>\d+)(?<suff>\D*)$");
var ordered = data.Select(d => (match: regex.Match(d), value: d))
    .Where(x => x.match.Success) //throw away anything that doesn't conform
    .Select(x => (
        x.value, 
        pre: x.match.Groups["pre"].Value, 
        num: int.Parse(x.match.Groups["num"].Value), 
        suff: x.match.Groups["suff"].Value))
    .OrderBy(x => x.num)
    .ThenBy(x => x.suff)
    .ThenBy(x => x.pre)
    .Select(x => x.value);

这是字母数字的
i比较者

编辑:添加代码示例

public class CustomStringComparer : IComparer<string>
{
    public int Compare(string first, string second)
    {
        var compareByCore = CompareCore(first, second);
        var compareBySuffix = CompareSuffix(first, second);
        var compareByPrefix = ComparePrefix(first, second);

        return compareByCore != 0 ? compareByCore 
            : compareBySuffix != 0 ? compareBySuffix
            : compareByPrefix;
    }

    private int CompareCore(string a, string b)
    {
        var firstCoreNumber = Regex.Match(a, @"\d+").Value;
        var secondCoreNumber = Regex.Match(b, @"\d+").Value;

        if (!string.IsNullOrEmpty(firstCoreNumber) && !string.IsNullOrEmpty(secondCoreNumber))
        {
            return int.Parse(firstCoreNumber).CompareTo(int.Parse(secondCoreNumber));
        }

        return 0;
    }

    private int CompareSuffix(string a, string b)
    {
        var firstSuffix = Regex.Match(a, @"\D+$").Value;
        var secondSuffix = Regex.Match(b, @"\D+$").Value;

        return firstSuffix.CompareTo(secondSuffix);
    }

    private int ComparePrefix(string a, string b)
    {
        var firstPrefix = Regex.Match(a, @"^\D+").Value;
        var secondPrefix = Regex.Match(b, @"^\D+").Value;

        return firstPrefix.CompareTo(secondPrefix);
    }
}
void Main()
{
var arr=新[]{“b2”、“a1a”、“5ac”、“1”、“12”、“2”、“11”、“5aa”、“3”、“5ab”、“a1”、“a2b”、“abb11ca”、“1b”、“aba11ca”};
var items=arr.OrderBy(x=>x.ToString(),new AlphanumComparator()).ToList();
Console.WriteLine(“排序数组:”);
foreach(项目中的var s)
{
Console.WriteLine(“{0}”,s);
}
}
公共类字母计算器:IComparer
{
私有枚举ChunkType{字母数字,数字};
私有布尔InChunk(char ch,char otherCh)
{
ChunkType类型=ChunkType.字母数字;
如果(字符为数字(其他字符))
{
type=ChunkType.Numeric;
}
if((type==ChunkType.Alphanumeric&&char.IsDigit(ch))
||(type==ChunkType.Numeric&&!char.IsDigit(ch)))
{
返回false;
}
返回true;
}
公共整数比较(对象x、对象y)
{
字符串s1=x作为字符串;
字符串s2=y作为字符串;
如果(s1==null | | s2==null)
{
返回0;
}
int thisMarker=0,thisNumericChunk=0;
int thatMarker=0,thatNumericChunk=0;
而((这个标记=s1.长度)
{
返回-1;
}
else if(该标记>=s2.长度)
{
返回1;
}
char thisCh=s1[thisMarker];
char-thatCh=s2[thattmarker];
StringBuilder thisChunk=新的StringBuilder();
StringBuilder thatChunk=新StringBuilder();
而((thisMarkerthatNumericChunk)
{
结果=1;
}
}
其他的
{
结果=thisChunk.ToString().CompareTo(thatChunk.ToString());
}
如果(结果!=0)
{
返回结果;
}
}
返回0;
}
}

这是字母数字的
比较者

编辑:添加代码示例

public class CustomStringComparer : IComparer<string>
{
    public int Compare(string first, string second)
    {
        var compareByCore = CompareCore(first, second);
        var compareBySuffix = CompareSuffix(first, second);
        var compareByPrefix = ComparePrefix(first, second);

        return compareByCore != 0 ? compareByCore 
            : compareBySuffix != 0 ? compareBySuffix
            : compareByPrefix;
    }

    private int CompareCore(string a, string b)
    {
        var firstCoreNumber = Regex.Match(a, @"\d+").Value;
        var secondCoreNumber = Regex.Match(b, @"\d+").Value;

        if (!string.IsNullOrEmpty(firstCoreNumber) && !string.IsNullOrEmpty(secondCoreNumber))
        {
            return int.Parse(firstCoreNumber).CompareTo(int.Parse(secondCoreNumber));
        }

        return 0;
    }

    private int CompareSuffix(string a, string b)
    {
        var firstSuffix = Regex.Match(a, @"\D+$").Value;
        var secondSuffix = Regex.Match(b, @"\D+$").Value;

        return firstSuffix.CompareTo(secondSuffix);
    }

    private int ComparePrefix(string a, string b)
    {
        var firstPrefix = Regex.Match(a, @"^\D+").Value;
        var secondPrefix = Regex.Match(b, @"^\D+").Value;

        return firstPrefix.CompareTo(secondPrefix);
    }
}
void Main()
{
var arr=新[]{“b2”、“a1a”、“5ac”、“1”、“12”、“2”、“11”、“5aa”、“3”、“5ab”、“a1”、“a2b”、“abb11ca”、“1b”、“aba11ca”};
var items=arr.OrderBy(x=>x.ToString(),new AlphanumComparator()).ToList();
Console.WriteLine(“排序数组:”);
foreach(项目中的var s)
{
Console.WriteLine(“{0}”,s);
}
}
公共类字母计算器:IComparer
{
私有枚举ChunkType{字母数字,数字};
私有布尔InChunk(char ch,char otherCh)
{
ChunkType类型=ChunkType.字母数字;
如果(字符为数字(其他字符))
{
type=ChunkType.Numeric;
}
if((type==ChunkType.Alphanumeric&&char.IsDigit(ch))
||(type==ChunkType.Numeric&&!char.IsDigit(ch)))
{
返回false;
}
返回true;
}
公共整数比较(对象x、对象y)
{
字符串s1=x作为字符串;
字符串s2=y作为字符串;
如果(s1==null | | s2==null)
{
返回0;
}
int thisMarker=0,thisNumericChunk=0;
int thatMarker=0,thatNumericChunk=0;
而((这个标记=s1.长度)
{
返回-1;
}
else if(该标记>=s2.长度)
{
返回1;
}
char thisCh=s1[thisMarker];
炭茅草=s2
public class CustomStringComparer : IComparer<string>
{
    public int Compare(string first, string second)
    {
        var compareByCore = CompareCore(first, second);
        var compareBySuffix = CompareSuffix(first, second);
        var compareByPrefix = ComparePrefix(first, second);

        return compareByCore != 0 ? compareByCore 
            : compareBySuffix != 0 ? compareBySuffix
            : compareByPrefix;
    }

    private int CompareCore(string a, string b)
    {
        var firstCoreNumber = Regex.Match(a, @"\d+").Value;
        var secondCoreNumber = Regex.Match(b, @"\d+").Value;

        if (!string.IsNullOrEmpty(firstCoreNumber) && !string.IsNullOrEmpty(secondCoreNumber))
        {
            return int.Parse(firstCoreNumber).CompareTo(int.Parse(secondCoreNumber));
        }

        return 0;
    }

    private int CompareSuffix(string a, string b)
    {
        var firstSuffix = Regex.Match(a, @"\D+$").Value;
        var secondSuffix = Regex.Match(b, @"\D+$").Value;

        return firstSuffix.CompareTo(secondSuffix);
    }

    private int ComparePrefix(string a, string b)
    {
        var firstPrefix = Regex.Match(a, @"^\D+").Value;
        var secondPrefix = Regex.Match(b, @"^\D+").Value;

        return firstPrefix.CompareTo(secondPrefix);
    }
}
var arr = new[]
        { "a1a", "5ac", "1", "12", "2", "11", "5aa", "3", "5ab", "a2b", "abb11ca", "1b", "aba11ca" };

    var sortedArr = arr.OrderBy(x => x, new CustomStringComparer());

    foreach (var s in sortedArr)
    {
        Console.Write($"{s} ");
    }
var comparer = new ComparerBuilder<string>()
    .SortKey(k => int.Parse(Regex.Match(k, @"\d+").Value))
        .ThenKey(k => Regex.Match(k, @"\D*$").Value)
        .ThenKey(k => Regex.Match(k, @"^\D*").Value)
        .Build();

var ordered = data.OrderBy(x => x, comparer);