在c#中有一个简单的方法来创建一个数字的序数吗?例如:
1返回第1位 2返回第2 3返回第3 等
这是否可以通过String.Format()来完成,或者是否有可用的函数来完成?
在c#中有一个简单的方法来创建一个数字的序数吗?例如:
1返回第1位 2返回第2 3返回第3 等
这是否可以通过String.Format()来完成,或者是否有可用的函数来完成?
当前回答
private static string GetOrd(int num) => $"{num}{(!(Range(11, 3).Any(n => n == num % 100) ^ Range(1, 3).All(n => n != num % 10)) ? new[] { "ˢᵗ", "ⁿᵈ", "ʳᵈ" }[num % 10 - 1] : "ᵗʰ")}";
如果有人在找一句俏皮话。
其他回答
你得自己动手了。在我的脑海中:
public static string Ordinal(this int number)
{
var work = number.ToString();
if ((number % 100) == 11 || (number % 100) == 12 || (number % 100) == 13)
return work + "th";
switch (number % 10)
{
case 1: work += "st"; break;
case 2: work += "nd"; break;
case 3: work += "rd"; break;
default: work += "th"; break;
}
return work;
}
你可以这样做
Console.WriteLine(432.Ordinal());
针对11/12/13例外进行了编辑。我确实从我的头顶说过:-)
为1011编辑-其他人已经修复了这个问题,只是想确保其他人不会抓取这个错误的版本。
根据其他答案:
public static string Ordinal(int n)
{
int r = n % 100, m = n % 10;
return (r<4 || r>20) && (m>0 && m<4) ? n+" stndrd".Substring(m*2,2) : n+"th";
}
虽然我还没有对此进行基准测试,但通过避免所有条件case语句,您应该能够获得更好的性能。
这是java,但是移植到c#很简单:
public class NumberUtil {
final static String[] ORDINAL_SUFFIXES = {
"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
};
public static String ordinalSuffix(int value) {
int n = Math.abs(value);
int lastTwoDigits = n % 100;
int lastDigit = n % 10;
int index = (lastTwoDigits >= 11 && lastTwoDigits <= 13) ? 0 : lastDigit;
return ORDINAL_SUFFIXES[index];
}
public static String toOrdinal(int n) {
return new StringBuffer().append(n).append(ordinalSuffix(n)).toString();
}
}
注意,如果在一个紧密循环中生成大量序数,减少条件和使用数组查找应该会提高性能。然而,我也承认这并不像case语句解决方案那样可读。
虽然这里有很多很好的答案,但我想还有另一个答案的空间,这一次是基于模式匹配,如果不是为了其他任何东西,那么至少是为了有争议的可读性
public static string Ordinals1(this int number)
{
switch (number)
{
case int p when p % 100 == 11:
case int q when q % 100 == 12:
case int r when r % 100 == 13:
return $"{number}th";
case int p when p % 10 == 1:
return $"{number}st";
case int p when p % 10 == 2:
return $"{number}nd";
case int p when p % 10 == 3:
return $"{number}rd";
default:
return $"{number}th";
}
}
这个溶液有什么特别之处呢?我只是为各种其他解决方案添加了一些性能考虑因素
坦率地说,我怀疑性能对于这种特定的场景真的很重要(谁真的需要数百万个数字的序数呢),但至少它提供了一些可供考虑的比较……
100万件供参考(当然,根据机器规格,您的米粒可能会有所不同) 使用模式匹配和划分(这个答案) ~ 622毫秒 使用模式匹配和字符串(这个答案) ~ 1967毫秒 有两个开关和划分(接受答案) ~ 637毫秒 用一个开关和除法(另一个答案) ~ 725毫秒
void Main()
{
var timer = new Stopwatch();
var numbers = Enumerable.Range(1, 1000000).ToList();
// 1
timer.Reset();
timer.Start();
var results1 = numbers.Select(p => p.Ordinals1()).ToList();
timer.Stop();
timer.Elapsed.TotalMilliseconds.Dump("with pattern matching and divisions");
// 2
timer.Reset();
timer.Start();
var results2 = numbers.Select(p => p.Ordinals2()).ToList();
timer.Stop();
timer.Elapsed.TotalMilliseconds.Dump("with pattern matching and strings");
// 3
timer.Reset();
timer.Start();
var results3 = numbers.Select(p => p.Ordinals3()).ToList();
timer.Stop();
timer.Elapsed.TotalMilliseconds.Dump("with two switches and divisons");
// 4
timer.Reset();
timer.Start();
var results4 = numbers.Select(p => p.Ordinals4()).ToList();
timer.Stop();
timer.Elapsed.TotalMilliseconds.Dump("with one switche and divisons");
}
public static class Extensions
{
public static string Ordinals1(this int number)
{
switch (number)
{
case int p when p % 100 == 11:
case int q when q % 100 == 12:
case int r when r % 100 == 13:
return $"{number}th";
case int p when p % 10 == 1:
return $"{number}st";
case int p when p % 10 == 2:
return $"{number}nd";
case int p when p % 10 == 3:
return $"{number}rd";
default:
return $"{number}th";
}
}
public static string Ordinals2(this int number)
{
var text = number.ToString();
switch (text)
{
case string p when p.EndsWith("11"):
return $"{number}th";
case string p when p.EndsWith("12"):
return $"{number}th";
case string p when p.EndsWith("13"):
return $"{number}th";
case string p when p.EndsWith("1"):
return $"{number}st";
case string p when p.EndsWith("2"):
return $"{number}nd";
case string p when p.EndsWith("3"):
return $"{number}rd";
default:
return $"{number}th";
}
}
public static string Ordinals3(this int number)
{
switch (number % 100)
{
case 11:
case 12:
case 13:
return $"{number}th";
}
switch (number % 10)
{
case 1:
return $"{number}st";
case 2:
return $"{number}nd";
case 3:
return $"{number}rd";
default:
return $"{number}th";
}
}
public static string Ordinals4(this int number)
{
var ones = number % 10;
var tens = Math.Floor(number / 10f) % 10;
if (tens == 1)
{
return $"{number}th";
}
switch (ones)
{
case 1:
return $"{number}th";
case 2:
return $"{number}nd";
case 3:
return $"{number}rd";
default:
return $"{number}th";
}
}
}
c# 8和9中接受的带有开关表达式和模式匹配的答案。
没有不必要的字符串转换或分配。
string.Concat(number, number < 0 ? "" : (number % 100) switch
{
11 or 12 or 13 => "th",
int n => (n % 10) switch
{
1 => "st",
2 => "nd",
3 => "rd",
_ => "th",
}
})
或者是不友好的一句话:
$"{number}{(number < 0 ? "" : (number % 100) switch { 11 or 12 or 13 => "th", int n => (n % 10) switch { 1 => "st", 2 => "nd", 3 => "rd", _ => "th" }})}"