按数字和空格排序

时间:2015-07-30 19:24:51

标签: 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搞乱排序的字符。例如,上面单位列表的正确顺序是:

  • NP111
  • NP112
  • NP 416
  • NP / 417A
  • NP / 418C
  • NP / 418F

如何使用LINQ以这种方式对单元进行排序?提前致谢。

3 个答案:

答案 0 :(得分:1)

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

例如:

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;
    }
}

稍后在您的代码中:

var sites = new[] { new Site { Id = "NP 417" }, new Site { Id = "NP 318" }, new Site { Id = "NP 418" }, new Site { Id = "NP111" }, new Site { Id = "NP112" } };

SortedSet<Site> orderedSites = new SortedSet<Site>(sites, new AscendingSiteComparer());

现在,默认情况下,您的网站将以升序进行订购。

正如我上面所说,你也可以在构建过程中直接构建排序集而不提供IEnumerable<T>

// While you add items in a disordered way, they're stored in the
// desired order!
SortedSet<Site> orderedSites = new SortedSet<Site>(new AscendingSiteComparer());
orderedSites.Add(new Site { Id = "NP 417" });
orderedSites.Add(new Site { Id = "NP 318" });
orderedSites.Add(new Site { Id = "NP111" });

在一天结束时,如果需要使用固定订单提供您的网站集,我将不会返回List<T>SortedSet<T>,因为其他方法可能会添加新项目,而他们&# 39; 按顺序存储,每当您想要重新订购该集合时,您都不需要.OrderBy(...)(直到您需要不同的顺序,当然......!)。

LINQ方式......

如果您认为排序集可能过度,则可以使用OrderBy扩展方法使用LINQ:

public class StringAscendingComparer : IComparer<string>
{
    private readonly static Regex replaceRegex = new Regex(@"[a-z]+\s*([0-9]+)$", RegexOptions.IgnoreCase);

    public int Compare(string x, string y)
    {

        int a = int.Parse(replaceRegex.Replace(x, "$1"));
        int b = int.Parse(replaceRegex.Replace(y, "$1"));

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

var orderedSites2 = sites.OrderBy(site => site.Id, new StringAscendingComparer());

答案 1 :(得分:1)

我倾向于使用这样的课程:

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 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

但你也可以像这样使用这段代码:

var ordered =
    from c in codes
    let code = new Code(c)
    orderby code.Prefix, code.Number, code.Suffix
    select c;

我通常会继续在此类上实现GetHashCodeEquals,以便能够将其用作词典中的键或用于分组目的。

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

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);
    }
}

答案 2 :(得分: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));