Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/290.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 自定义数组排序_C#_.net_Arrays - Fatal编程技术网

C# 自定义数组排序

C# 自定义数组排序,c#,.net,arrays,C#,.net,Arrays,数组中的每个项/字符串都以两个字母开头,后跟两个或三个数字,有时还后跟另一个字母 示例,RS01 RS10 RS32A RS102 RS80 RS05A RS105A RS105B 我尝试使用默认数组对其进行排序。排序结果是 RS01 RS05A RS10 RS102 RS105A RS105B RS32A RS80 但我需要像这样 RS01 RS05A RS10 RS32A RS80 RS102 RS105A RS105B 有什么想法吗?您需要编写一个自定义比较器类来实现IComparer

数组中的每个项/字符串都以两个字母开头,后跟两个或三个数字,有时还后跟另一个字母

示例,
RS01 RS10 RS32A RS102 RS80 RS05A RS105A RS105B

我尝试使用默认数组对其进行排序。排序结果是

RS01
RS05A
RS10
RS102
RS105A
RS105B
RS32A
RS80
但我需要像这样

RS01
RS05A
RS10
RS32A
RS80
RS102
RS105A
RS105B

有什么想法吗?

您需要编写一个自定义比较器类来实现
IComparer
;将字符串分解为组件非常简单。调用
Array.Sort
时,给它一个比较器实例,就可以得到所需的结果。

下面是使用自定义比较委托和正则表达式进行排序:

string[] array = { "RS01", "RS10", "RS32A", "RS102", 
                   "RS80", "RS05A", "RS105A", "RS105B" };

Array.Sort(array, (s1, s2) =>
    {
        Regex regex = new Regex(@"([a-zA-Z]+)(\d+)([a-zA-Z]*)");
        var match1 = regex.Match(s1);                                        
        var match2 = regex.Match(s2);

        // prefix
        int result = match1.Groups[1].Value.CompareTo(match2.Groups[1].Value);
        if (result != 0)
            return result;

        // number 
        result = Int32.Parse(match1.Groups[2].Value)
                        .CompareTo(Int32.Parse(match2.Groups[2].Value));

        if (result != 0)
            return result;

        // suffix
        return match1.Groups[3].Value.CompareTo(match2.Groups[3].Value);
    });

更新(少量重构,并将所有内容移动到单独的比较器类)。用法:

比较器本身:

public class RSComparer : IComparer<string>
{
    private Dictionary<string, RS> entries = new Dictionary<string, RS>();

    public int Compare(string x, string y)
    {
        if (!entries.ContainsKey(x))
            entries.Add(x, new RS(x));

        if (!entries.ContainsKey(y))
            entries.Add(y, new RS(y));

        return entries[x].CompareTo(entries[y]);
    }

    private class RS : IComparable
    {
        public RS(string value)
        {
            Regex regex = new Regex(@"([A-Z]+)(\d+)([A-Z]*)");
            var match = regex.Match(value);
            Prefix = match.Groups[1].Value;
            Number = Int32.Parse(match.Groups[2].Value);
            Suffix = match.Groups[3].Value;
        }

        public string Prefix { get; private set; }
        public int Number { get; private set; }
        public string Suffix { get; private set; }

        public int CompareTo(object obj)
        {
            RS rs = (RS)obj;
            int result = Prefix.CompareTo(rs.Prefix);
            if (result != 0)
                return result;

            result = Number.CompareTo(rs.Number);
            if (result != null)
                return result;

            return Suffix.CompareTo(rs.Suffix);
        }
    }
}
公共类RSComparer:IComparer
{
专用词典条目=新词典();
公共整数比较(字符串x、字符串y)
{
如果(!entries.ContainsKey(x))
增加(x,新RS(x));
如果(!entries.ContainsKey(y))
增加(y,新RS(y));
返回条目[x]。比较(条目[y]);
}
私有类RS:IComparable
{
公共RS(字符串值)
{
正则表达式正则表达式=新正则表达式(@“([A-Z]+)(\d+)([A-Z]*)”;
var match=regex.match(值);
前缀=匹配。组[1]。值;
Number=Int32.Parse(match.Groups[2].Value);
后缀=匹配。组[3]。值;
}
公共字符串前缀{get;private set;}
公共整数{get;private set;}
公共字符串后缀{get;private set;}
公共整数比较(对象对象对象)
{
RS=(RS)obj;
int result=前缀.CompareTo(rs.Prefix);
如果(结果!=0)
返回结果;
结果=编号。比较(rs编号);
如果(结果!=null)
返回结果;
返回后缀.CompareTo(rs.Suffix);
}
}
}

您可以使用此linq查询:

var strings = new[] { 
    "RS01","RS05A","RS10","RS102","RS105A","RS105B","RS32A","RS80"
};
strings = strings.Select(str => new
{
    str,
    num = int.Parse(String.Concat(str.Skip(2).TakeWhile(Char.IsDigit))),
    version = String.Concat(str.Skip(2).SkipWhile(Char.IsDigit))
})
.OrderBy(x => x.num).ThenBy(x => x.version)
.Select(x => x.str)
.ToArray();

结果:

RS01
RS05A
RS10
RS32A
RS80
RS102
RS105A
RS105B

您使用的是什么.net框架?它总是以“RS”开头吗?如果不是,是否要先按字母顺序排序,然后按数字排序?它总是以“RS”开头。是否要将字符串中的数字作为数字而不是字符串?我发誓在Win32中有这样的东西…@Sammy如果它总是以“RS”开头,我建议只修剪它,然后在完成后再添加它;这可能会使解析变得更容易。然后只需检查最后一个字符是否为字母;如果是,则存储它并从一开始就解析数字,如果不是,则将整个内容解析为一个数字。看起来这是唯一可行的解决方案。在开始排序之前进行分析可能会更好,这样您就不会一遍又一遍地分析每一个,但对于一个小数据集来说,这不是问题。@Servy谢谢!是的,这是有效的,验证:)事实上,我最好使用比较器而不是委托(代码不会那么凌乱)@Sammy看看更新的答案-我做了一个比较器,这样你的代码会看起来更干净。此外,我还创建了用于保存前缀、数字和后缀的内部类RS(可能您希望在应用程序中使用该类而不是字符串)。最后一件事——比较器保存已经解析的实体,所以这次效率更高:)@granadaCoder:Linq并不总是更好。但它可以更具可读性和更短(并非总是如此)。它也不总是最有效的,但通常这并不重要。
RS01
RS05A
RS10
RS32A
RS80
RS102
RS105A
RS105B