C# 使用数字和空格按字符串排序

C# 使用数字和空格按字符串排序,c#,linq,C#,Linq,我有一个以“代码”命名的单元列表,显示如下: NP/417A NP 416 NP/418F NP/418C NP111 NP112 从以下对象中的数据库查询这些单位: var units = _unitService.GetBySiteId(site.SiteId); 然后可用于按“代码”订购装置: units = units.OrderBy(u => u.Code); 但是,如果单位代码相同,我需要单位以数字和字母顺序显示,同时忽略任何空格或/字符,使LINQ的顺序混乱。。例如,上述

我有一个以“代码”命名的单元列表,显示如下:

NP/417A NP 416 NP/418F NP/418C NP111 NP112 从以下对象中的数据库查询这些单位:

var units = _unitService.GetBySiteId(site.SiteId);
然后可用于按“代码”订购装置:

units = units.OrderBy(u => u.Code);
但是,如果单位代码相同,我需要单位以数字和字母顺序显示,同时忽略任何空格或/字符,使LINQ的顺序混乱。。例如,上述单元列表的正确顺序为:

NP111 NP112 NP 416 NP/417A NP/418C NP/418F
如何使用LINQ以这种方式对单元进行排序?提前谢谢

一种可能的方法是使用排序集。您可以将值直接存储到排序集,也可以构建一个排序集,以使值按照某些条件排序,作为方法的返回值

例如:

public class Site
{
    public string Id { get; set; }
}

public class AscendingSiteComparer : IComparer<Site>
{
    // Maybe it's not the best regular expression ever, but if your site
    // ids start with letters either in capital or lower case, it will
    // work!
    private readonly static Regex replaceRegex = new Regex(@"[a-z]+\s*([0-9]+)$", RegexOptions.IgnoreCase);

    public int Compare(Site x, Site y)
    {
        int a = int.Parse(replaceRegex.Replace(x.Id, "$1"));
        int b = int.Parse(replaceRegex.Replace(y.Id, "$1"));

        if (a > b)
            return 1;
        else if (a < b)
            return -1;
        else
            return 0;
    }
}

根据您的需要,选择以下任一选项:

/* Remove spaces and sort */
.OrderBy(u=>u.Replace(" ",""))

/* Sort based on last 3 characters */
.OrderBy(u=>u.Substring(u.Length-3))

 /* Sort based on last 3 characters as integer */
.OrderBy(u=>int.Parse(u.Substring(u.Length-3)))

/* Remove all non-digits and sort as string */
.OrderBy(u=>Regex.Replace(u,"[^0-9]",""));

/* Remove all non-digits and sort as integer */
.OrderBy(u=>int.Parse(Regex.Replace(u,"[^0-9]","")));

/* Pull out all the digits and sort as integer */
.OrderBy(u=>int.Parse(Regex.Match(u,"([0-9]+)").Groups[1].Value));

我倾向于使用这样的类:

public class Code
{
    private Match _match = null;
    public Code(string raw)
    {
        _match = Regex.Match(raw, @"^([A-Z]*)([^0-9]*)(\d+)(.*)$");
    }
    public string Prefix { get { return _match.Groups[1].Value; } }
    public string Separator { get { return _match.Groups[2].Value; } }
    public int Number { get { return int.Parse(_match.Groups[3].Value); } }
    public string Suffix { get { return _match.Groups[4].Value; } }
    public override string ToString()
    {
        return String.Format("{0}/{1:00000}{2}", this.Prefix, this.Number, this.Suffix);
    }
}
var ordered =
    from c in codes
    let code = new Code(c)
    orderby code.Prefix, code.Number, code.Suffix
    select c;
public class Code
{
    public Code(string raw)
    {
        if (raw == "SUITE FIVE")
        {
            this.Prefix = raw;
            this.Separator = "/";
            this.Number = 0;
            this.Suffix = "";
        }
        else
        {
            var match = Regex.Match(raw, @"^([A-Z]*)([^0-9]*)(\d+)(.*)$");
            this.Prefix = match.Groups[1].Value;
            this.Separator = match.Groups[2].Value;
            this.Number = int.Parse(match.Groups[3].Value);
            this.Suffix = match.Groups[4].Value;
        }
    }
    public string Prefix { get; private set; }
    public string Separator { get; private set; }
    public int Number { get; private set; }
    public string Suffix { get; private set; }
    public override string ToString()
    {
        return String.Format("{0}/{1:00000}{2}", this.Prefix, this.Number, this.Suffix);
    }
}
那么就这样做:

var codes = new []
{
    "NP/417A",
    "NP 416",
    "NP/418F",
    "NP/418C",
    "NP111",
    "NP112",
};

var ordered = codes.OrderBy(c => new Code(c).ToString()).ToArray();
其中:

NP111
NP112
NP 416
NP/417A
NP/418C
NP/418F
但您也可以这样使用此代码:

public class Code
{
    private Match _match = null;
    public Code(string raw)
    {
        _match = Regex.Match(raw, @"^([A-Z]*)([^0-9]*)(\d+)(.*)$");
    }
    public string Prefix { get { return _match.Groups[1].Value; } }
    public string Separator { get { return _match.Groups[2].Value; } }
    public int Number { get { return int.Parse(_match.Groups[3].Value); } }
    public string Suffix { get { return _match.Groups[4].Value; } }
    public override string ToString()
    {
        return String.Format("{0}/{1:00000}{2}", this.Prefix, this.Number, this.Suffix);
    }
}
var ordered =
    from c in codes
    let code = new Code(c)
    orderby code.Prefix, code.Number, code.Suffix
    select c;
public class Code
{
    public Code(string raw)
    {
        if (raw == "SUITE FIVE")
        {
            this.Prefix = raw;
            this.Separator = "/";
            this.Number = 0;
            this.Suffix = "";
        }
        else
        {
            var match = Regex.Match(raw, @"^([A-Z]*)([^0-9]*)(\d+)(.*)$");
            this.Prefix = match.Groups[1].Value;
            this.Separator = match.Groups[2].Value;
            this.Number = int.Parse(match.Groups[3].Value);
            this.Suffix = match.Groups[4].Value;
        }
    }
    public string Prefix { get; private set; }
    public string Separator { get; private set; }
    public int Number { get; private set; }
    public string Suffix { get; private set; }
    public override string ToString()
    {
        return String.Format("{0}/{1:00000}{2}", this.Prefix, this.Number, this.Suffix);
    }
}
我通常会在这个类上实现GetHashCode和Equals,以便能够将其用作字典中的键或用于分组目的

为了处理其他情况,我会考虑做一些简单的事情,比如:

public class Code
{
    private Match _match = null;
    public Code(string raw)
    {
        _match = Regex.Match(raw, @"^([A-Z]*)([^0-9]*)(\d+)(.*)$");
    }
    public string Prefix { get { return _match.Groups[1].Value; } }
    public string Separator { get { return _match.Groups[2].Value; } }
    public int Number { get { return int.Parse(_match.Groups[3].Value); } }
    public string Suffix { get { return _match.Groups[4].Value; } }
    public override string ToString()
    {
        return String.Format("{0}/{1:00000}{2}", this.Prefix, this.Number, this.Suffix);
    }
}
var ordered =
    from c in codes
    let code = new Code(c)
    orderby code.Prefix, code.Number, code.Suffix
    select c;
public class Code
{
    public Code(string raw)
    {
        if (raw == "SUITE FIVE")
        {
            this.Prefix = raw;
            this.Separator = "/";
            this.Number = 0;
            this.Suffix = "";
        }
        else
        {
            var match = Regex.Match(raw, @"^([A-Z]*)([^0-9]*)(\d+)(.*)$");
            this.Prefix = match.Groups[1].Value;
            this.Separator = match.Groups[2].Value;
            this.Number = int.Parse(match.Groups[3].Value);
            this.Suffix = match.Groups[4].Value;
        }
    }
    public string Prefix { get; private set; }
    public string Separator { get; private set; }
    public int Number { get; private set; }
    public string Suffix { get; private set; }
    public override string ToString()
    {
        return String.Format("{0}/{1:00000}{2}", this.Prefix, this.Number, this.Suffix);
    }
}

@dib是否仅按每个对象中的值进行排序?如果是这种情况,只需将字母表替换为空白并转换为整数。NP 213和NP 31应该如何排序?请检查此项:。我进行了测试,它似乎解决了您的问题。如果您的样本输入和样本输出数据匹配,那就太好了。为什么您要使用类,而您可以使用IComparer?当然,这是一门课,但这是标准approach@MatíasFidemraizer-我同意IComparer是提供自定义排序的标准方法。然而,像这样的自定义类提供了一种类似于视图模型的方法来分解代码并对其应用自定义逻辑。orderby code.Prefix、code.Number、code.Suffix这行就是一个很好的例子-它在排序时更明确地说明了发生了什么。比ORDERBYDATECOMARER类名更明确。。。我不确定我是否希望看到用于排序的字段的内部结构,而不仅仅是一个按某个条件名称排序的排序集。。。顺便说一句,这只是我的意见!!!感谢各位,我发现这个解决方案更适合实现,更干净,所以将此标记为正确答案。此外,在其中一个表数据上,它还包含一个单元代码,如suitefive,这会导致RegEx在匹配项上查找int失败。改变regex/类是否是允许此格式与其他格式一起使用的最佳方式?您当然可以更改regex,但如果您有太多的奇数代码,则可能需要在构造函数中解构并只分配属性。这可能更简单。我会看看是否可以添加那个类。