[英]Alphabetical order, Array.Sort() doesn't work well
我的字母顺序有问题。 Array.Sort() 在我的情况下效果不佳。
string str = "AaBbCc";
char[] arr = second.ToCharArray();
Array.Sort(arr);
// Output: ABCabc
// I need: AaBbCc
有任何想法吗?
您可以使用 LINQ 实现您的目标。
首先,我们需要将您的字符分解为一系列单个字符串。 我们可以通过选择做到这一点。
str.Select(x => x.ToString())
好的,现在我们要对这个列表进行排序。 字符串的默认排序是单词排序,它会像aAbBcC
一样aAbBcC
。 由于您想先获取大写字母,我们将使用OrdinalIgnoreCase
比较器,它将我们的字符分组。
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)
好的,现在我们已经对我们的角色进行了分组。 我们现在要使用 ThenBy 按顺序对这些组进行排序,以使大写字母排在最前面。
.ThenBy(x => x, StringComparer.Ordinal)
最后,我们可以把它变成一个数组。
.ToArray();
把它放在一起,我们得到以下内容:
var res = str.Select(x => x.ToString())
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)
.ThenBy(x => x, StringComparer.Ordinal)
.ToArray();
这给了我们一个看起来像这样的数组: ["A","a","B","b","C","c"]
此时,正如@dvo 所指出的,我们可以通过调用 String.Join 将其转换回单个字符串,如下所示:
var resStr = string.Join("", res);
正如@RufusL 指出的那样,我们可以为这个查询做更多的事情。 因为我们知道我们最终想要一个字符串,所以我们可以完全跳过ToArray
调用并坚持使用IOrderedEnumerable<string>
。
var res = str.Select(x => x.ToString())
.OrderBy(x => x, StringComparer.OrdinalIgnoreCase)
.ThenBy(x => x, StringComparer.Ordinal);
因为我们没有用字符串连接任何东西,所以我们可以使用string.Concat
而不是string.Join
。
var resStr = string.Concat(res);
问题是您的代码按 ASCII 值排序,大写 ( AZ
) 为65-90
,小写 ( az
) 为97-122
。
假设您总是希望大写字母出现在小写字母之前,我们可以使用一个小技巧,通过在进行比较之前从 ASCII 值中减去31.5
,将小写字母排在大写值之后。
通过这样做, a
变为65.5
( 97 - 31.5
) 并将在A
( 65
) 和B
( 66
) 之间排序。 对于所有其他小写字母也是如此。 这避免了创建一堆新字符串进行比较和进行多次排序的成本。
例如:
string str = "zZYyabCABcxX";
string ordered = string.Concat(str.OrderBy(c => c > 96 && c < 123 ? c - 31.5 : c));
Console.WriteLine(ordered);
我们还可以使用char.IsUpper
和char.ToLower
代替硬编码的 ascii 值:
// If the character is lower-case, use the value of its upper-case counterpart plus .5
ordered = string.Concat(str.OrderBy(c => char.IsLower(c) ? char.ToUpper(c) + .5 : c));
输出:
编辑
要回答其中一条评论,如果您想使用相同的方法对字符进行排序,使小写字母排在大写字母之前,那么如果该字符在大写范围内,您将减去32.5
。 这样a
( 97
) 变成64.5
( 97 - 32.5
) 并且将在A
( 65
) 之前排序:
string ordered = string.Concat(str.OrderBy(c => c > 96 && c < 123 ? c - 32.5 : c));
或者使用带有char.IsLower
和char.ToUpper
的技巧而不是硬编码的 ascii 值:
// If the character is lower-case, use the value of its upper-case counterpart minus .5
ordered = string.Concat(str.OrderBy(c => char.IsLower(c) ? char.ToUpper(c) - .5 : c));
还有一个不需要对 ASCII 值进行数学运算的解决方案:我们可以首先对字符进行排序,以便使用OrderBy(char.ToLower)
(按小写字符的 ASCII 值),然后我们可以通过char.IsLower
对它们进行char.IsLower
,然后将小写字符排在大写字符之后:
string str = "zZYyabCABcxX";
string ordered = string.Concat(str.OrderBy(char.ToLower).ThenBy(char.IsLower));
// ordered == "AaBbCcXxYyZz"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.