我有一个由'代码'命名的单位列表。并显示如下:
在以下对象中从数据库中查询这些单位:
var units = _unitService.GetBySiteId(site.SiteId);
然后可以使用以下代码对单位进行排序'代码':
units = units.OrderBy(u => u.Code);
但是,我需要单位以数字方式显示,如果它们是相同的单位代码,也要按字母顺序显示,也忽略任何空格或" /"使用LINQ搞乱排序的字符。例如,上面单位列表的正确顺序是:
如何使用LINQ以这种方式对单元进行排序?提前致谢。
答案 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(...)
(直到您需要不同的顺序,当然......!)。
如果您认为排序集可能过度,则可以使用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;
我通常会继续在此类上实现GetHashCode
和Equals
,以便能够将其用作词典中的键或用于分组目的。
为了处理其他情况,我会考虑做一些简单的事情,如下所示:
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));