Apakah ada cara mudah untuk membuat tata cara di C #?


202

Apakah ada cara mudah dalam C # untuk membuat Ordinals untuk suatu angka? Sebagai contoh:

  • 1 mengembalikan 1
  • 2 mengembalikan 2
  • 3 mengembalikan 3
  • ... dll

Apakah ini dapat dilakukan melalui String.Format()atau ada fungsi yang tersedia untuk melakukan ini?

Jawaban:


311

Halaman ini memberi Anda daftar lengkap semua aturan pemformatan angka khusus:

http://msdn.microsoft.com/en-us/library/0c899ak8.aspx

Seperti yang Anda lihat, tidak ada di sana tentang ordinals, sehingga tidak dapat dilakukan dengan menggunakan String.Format. Namun itu tidak terlalu sulit untuk menulis fungsi untuk melakukannya.

public static string AddOrdinal(int num)
{
    if( num <= 0 ) return num.ToString();

    switch(num % 100)
    {
        case 11:
        case 12:
        case 13:
            return num + "th";
    }

    switch(num % 10)
    {
        case 1:
            return num + "st";
        case 2:
            return num + "nd";
        case 3:
            return num + "rd";
        default:
            return num + "th";
    }
}

Pembaruan: Secara Teknis tidak ada untuk <= 0, jadi saya telah memperbarui kode di atas. Juga menghapus ToString()metode yang berlebihan .

Perhatikan juga, ini tidak diinternasionalkan. Saya tidak tahu seperti apa tata cara dalam bahasa lain.


2
Assert.AreEqual ("0", AddOrdinal (0)); Lihat wisegeek.com/what-is-an-ordinal-number.htm
si618

2
Menggunakan metode ekstensi (atau apa pun namanya - lihat jawaban @ Stu) akan bekerja dengan baik di sini. @ Si, Menambahkan kondisi itu akan sangat mudah jika diperlukan.
strager

12
Lupa tentang '11, 12 13' ... harus menjadi pertanyaan wawancara. :-)
Holf

2
Ya, programmer juga aneh;)
samjudson

2
@IanWarburton Tidak ada redundansi karena hanya satu pernyataan pengembalian yang akan ditampilkan. Jika Anda tidak puas dengan jawabannya, berikan jawaban Anda sendiri, tunjukkan kami cara yang "tepat" untuk melakukan ini, dan mengapa itu penting.
B2K

73

Ingat internasionalisasi!

Solusi di sini hanya berfungsi untuk bahasa Inggris. Banyak hal menjadi lebih rumit jika Anda perlu mendukung bahasa lain.

Misalnya, dalam bahasa Spanyol "1" akan ditulis sebagai "1.o", "1.a", "1.os" atau "1.as" tergantung pada apakah hal yang Anda hitung adalah maskulin, feminin atau jamak. !

Jadi, jika perangkat lunak Anda perlu mendukung berbagai bahasa, cobalah untuk menghindari peraturan.


7
@ Andomar: "2 pembaca pertama" => dalam bahasa Italia (dan Spanyol juga, saya kira) "pertama" adalah jamak di sini. Jadi Anda memiliki maskulin tunggal, feminin tunggal, maskulin jamak, feminin jamak; mungkin beberapa bahasa juga memiliki kasus yang netral (distinguing hal dari pria / hewan)
M.Turrini

2
Yang mengatakan, Anda tidak harus menghindari peraturan: memasukkannya ke dalam pelokalan, setelah Anda tahu semua kasus yang bisa Anda hadapi, atau (membuat pelanggan Anda) menerima beberapa batasan.
M.Turrini

26
Ini menjelaskan mengapa tim .NET menghindari menambahkannya ke format DateTime
Chris S

moment.js memiliki fungsi pemformatan "ordinal" oleh lokal sehingga tampaknya bisa dilakukan, juga berharap mereka akan melakukannya di .NET untuk DateTime
Guillaume86

5
Semuanya akan sangat sederhana jika Anda semua menggunakan "." karakter untuk ordinals, seperti yang kita lakukan dalam bahasa Jerman))))) 2. 2. 3. 4. 5., dll. Meskipun algoritme akan jauh lebih menarik jika seseorang menuliskan nomornya, dan harus menambahkan infleksi dalam 4 kasus tata bahasa dengan 3 artikel berbeda, di samping kasus tunggal dan jamak dari 12 kombinasi berbeda. Kalau dipikir-pikir, jangan Rusia memiliki 2 lebih, ditambah vocativ, dan beberapa bahasa nordic memiliki 15, saya pikir. Saya ingin sekali melihat implementasi itu dalam .NET.
Stefan Steiger

22

Versi saya versi Jesse versi Stu dan samjudson :)

Termasuk pengujian unit untuk menunjukkan bahwa jawaban yang diterima salah ketika angka <1

    /// <summary>
    /// Get the ordinal value of positive integers.
    /// </summary>
    /// <remarks>
    /// Only works for english-based cultures.
    /// Code from: http://stackoverflow.com/questions/20156/is-there-a-quick-way-to-create-ordinals-in-c/31066#31066
    /// With help: http://www.wisegeek.com/what-is-an-ordinal-number.htm
    /// </remarks>
    /// <param name="number">The number.</param>
    /// <returns>Ordinal value of positive integers, or <see cref="int.ToString"/> if less than 1.</returns>
    public static string Ordinal(this int number)
    {
        const string TH = "th";
        string s = number.ToString();

        // Negative and zero have no ordinal representation
        if (number < 1)
        {
            return s;
        }

        number %= 100;
        if ((number >= 11) && (number <= 13))
        {
            return s + TH;
        }

        switch (number % 10)
        {
            case 1: return s + "st";
            case 2: return s + "nd";
            case 3: return s + "rd";
            default: return s + TH;
        }
    }

    [Test]
    public void Ordinal_ReturnsExpectedResults()
    {
        Assert.AreEqual("-1", (1-2).Ordinal());
        Assert.AreEqual("0", 0.Ordinal());
        Assert.AreEqual("1st", 1.Ordinal());
        Assert.AreEqual("2nd", 2.Ordinal());
        Assert.AreEqual("3rd", 3.Ordinal());
        Assert.AreEqual("4th", 4.Ordinal());
        Assert.AreEqual("5th", 5.Ordinal());
        Assert.AreEqual("6th", 6.Ordinal());
        Assert.AreEqual("7th", 7.Ordinal());
        Assert.AreEqual("8th", 8.Ordinal());
        Assert.AreEqual("9th", 9.Ordinal());
        Assert.AreEqual("10th", 10.Ordinal());
        Assert.AreEqual("11th", 11.Ordinal());
        Assert.AreEqual("12th", 12.Ordinal());
        Assert.AreEqual("13th", 13.Ordinal());
        Assert.AreEqual("14th", 14.Ordinal());
        Assert.AreEqual("20th", 20.Ordinal());
        Assert.AreEqual("21st", 21.Ordinal());
        Assert.AreEqual("22nd", 22.Ordinal());
        Assert.AreEqual("23rd", 23.Ordinal());
        Assert.AreEqual("24th", 24.Ordinal());
        Assert.AreEqual("100th", 100.Ordinal());
        Assert.AreEqual("101st", 101.Ordinal());
        Assert.AreEqual("102nd", 102.Ordinal());
        Assert.AreEqual("103rd", 103.Ordinal());
        Assert.AreEqual("104th", 104.Ordinal());
        Assert.AreEqual("110th", 110.Ordinal());
        Assert.AreEqual("111th", 111.Ordinal());
        Assert.AreEqual("112th", 112.Ordinal());
        Assert.AreEqual("113th", 113.Ordinal());
        Assert.AreEqual("114th", 114.Ordinal());
        Assert.AreEqual("120th", 120.Ordinal());
        Assert.AreEqual("121st", 121.Ordinal());
        Assert.AreEqual("122nd", 122.Ordinal());
        Assert.AreEqual("123rd", 123.Ordinal());
        Assert.AreEqual("124th", 124.Ordinal());
    }

15

Sederhana, bersih, cepat

    private static string GetOrdinalSuffix(int num)
    {
        if (num.ToString().EndsWith("11")) return "th";
        if (num.ToString().EndsWith("12")) return "th";
        if (num.ToString().EndsWith("13")) return "th";
        if (num.ToString().EndsWith("1")) return "st";
        if (num.ToString().EndsWith("2")) return "nd";
        if (num.ToString().EndsWith("3")) return "rd";
        return "th";
    }

Atau lebih baik lagi, sebagai metode ekstensi

public static class IntegerExtensions
{
    public static string DisplayWithSuffix(this int num)
    {
        if (num.ToString().EndsWith("11")) return num.ToString() + "th";
        if (num.ToString().EndsWith("12")) return num.ToString() + "th";
        if (num.ToString().EndsWith("13")) return num.ToString() + "th";
        if (num.ToString().EndsWith("1")) return num.ToString() + "st";
        if (num.ToString().EndsWith("2")) return num.ToString() + "nd";
        if (num.ToString().EndsWith("3")) return num.ToString() + "rd";
        return num.ToString() + "th";
    }
}

Sekarang Anda bisa menelepon

int a = 1;
a.DisplayWithSuffix(); 

atau bahkan langsung

1.DisplayWithSuffix();

14

Anda harus menggulung sendiri. Dari atas kepala saya:

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

Anda kemudian bisa melakukannya

Console.WriteLine(432.Ordinal());

Diedit untuk pengecualian 11/12/13. SAYA TIDAK MENGATAKAN dari atas kepala saya :-)

Diedit untuk 1011 - orang lain sudah memperbaiki ini, hanya ingin memastikan orang lain tidak mengambil versi yang salah ini.


12

Saya lebih suka elemen dari kedua solusi Stu dan samjudson dan bekerja bersama menjadi apa yang saya pikir adalah kombo yang dapat digunakan:

    public static string Ordinal(this int number)
    {
        const string TH = "th";
        var s = number.ToString();

        number %= 100;

        if ((number >= 11) && (number <= 13))
        {
            return s + TH;
        }

        switch (number % 10)
        {
            case 1:
                return s + "st";
            case 2:
                return s + "nd";
            case 3:
                return s + "rd";
            default:
                return s + TH;
        }
    }

1
apa alasan di balik menggunakan konstanta untuk "th"?
nickf

karena digunakan dua kali dalam kode. Hanya menggunakan kebijaksanaan kuno yang tidak boleh Anda ulangi sendiri :) Dalam hal ini, runtime .NET hanya akan membuat satu salinan string sementara dengan dua "th" dalam kode, akan ada dua string yang dibuat dan dirujuk dalam memori.
Jesse C. Slicer

25
dan juga, jika nilai TH berubah, Anda akan ditetapkan.
Eclipse

7
@Jesse - Anda mendapatkan +1 saya, tapi saya tidak percaya. NET menangani string dengan cara ini, lihat yoda.arachsys.com/csharp/strings.html#interning , bacaan saya tentang masing-masing referensi ke literal "th" akan referensi bit memori yang sama. Tapi saya setuju tentang DRY :)
si618

4
Menghapus duplikasi seperti ini hanya menghambat keterbacaan saya pikir, maka kebingungan "Mengapa TH?" Saya tidak berpikir KERING harus ditafsirkan sebagai 'menghapus semua duplikasi apa pun biayanya'.
LihatNoWeevil

8

Meskipun saya belum membandingkan ini, Anda harus bisa mendapatkan kinerja yang lebih baik dengan menghindari semua pernyataan kasus bersyarat.

Ini java, tetapi port ke C # adalah sepele:

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

Catatan, pengurangan persyaratan dan penggunaan pencarian array harus mempercepat kinerja jika menghasilkan banyak ordinals dalam loop ketat. Namun, saya juga mengakui bahwa ini tidak dapat dibaca sebagai solusi pernyataan kasus.


Maaf saya membandingkan ini dalam C #, versi Anda tidak lebih cepat dari solusi si618.
GY_

periksa jawaban ini stackoverflow.com/a/58378465/2583579 untuk beberapa tolok ukur
Dan Dohotaru

3

Mirip dengan solusi Ryan, tetapi bahkan lebih mendasar, saya hanya menggunakan array biasa dan menggunakan hari untuk mencari ordinal yang benar:

private string[] ordinals = new string[] {"","st","nd","rd","th","th","th","th","th","th","th","th","th","th","th","th","th","th","th","th","th","st","nd","rd","th","th","th","th","th","th","th","st" };
DateTime D = DateTime.Now;
String date = "Today's day is: "+ D.Day.ToString() + ordinals[D.Day];

Saya belum memiliki kebutuhan, tetapi saya akan menganggap Anda dapat menggunakan array multidimensi jika Anda ingin memiliki dukungan banyak bahasa.

Dari apa yang saya ingat dari masa Uni saya, metode ini membutuhkan usaha minimal dari server.


2

Saya menggunakan kelas ekstensi ini:

public static class Int32Extensions
{
    public static string ToOrdinal(this int i)
    {
        return (i + "th")
            .Replace("1th", "1st")
            .Replace("2th", "2nd")
            .Replace("3th", "3rd");
    }
}

11, 12, 13
Kcoder

2

Versi samjudson yang diminta "kurang redundansi" ...

public static string AddOrdinal(int number)
{
    if (number <= 0) return number.ToString();

    string GetIndicator(int num)
    {
        switch (num % 100)
        {
            case 11:
            case 12:
            case 13:
                return "th";
        }

        switch (num % 10)
        {
            case 1:
                return "st";
            case 2:
                return "nd";
            case 3:
                return "rd";
            default:
                return "th";
        }
    }

    return number + GetIndicator(number);
}

2
Saya akan mengekspos "GetIndicator" sebagai public staticdan mengubah nama menjadi nama yang lebih mnemonik (yaitu "OrdinalSuffix"). Penelepon mungkin menginginkan bagian nomor dalam format yang berbeda (yaitu dengan koma).
Tom

2
        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] : "ᵗʰ")}";

Jika ada yang mencari satu liner: p


1
public static string OrdinalSuffix(int ordinal)
{
    //Because negatives won't work with modular division as expected:
    var abs = Math.Abs(ordinal); 

    var lastdigit = abs % 10; 

    return 
        //Catch 60% of cases (to infinity) in the first conditional:
        lastdigit > 3 || lastdigit == 0 || (abs % 100) - lastdigit == 10 ? "th" 
            : lastdigit == 1 ? "st" 
            : lastdigit == 2 ? "nd" 
            : "rd";
}

1

EDIT : Seperti YM_Industries tunjukkan dalam komentar, jawaban samjudson TIDAK bekerja untuk angka lebih dari 1000, komentar nick tampaknya telah hilang, dan saya tidak dapat mengingat apa masalah yang saya lihat. Tinggalkan jawaban ini di sini untuk penentuan waktu perbandingan.

Banyak sekali dari ini tidak bekerja untuk angka> 999, karena nickf ditunjukkan oleh dalam komentar (EDIT: sekarang hilang).

Berikut ini adalah versi didasarkan dari versi modifikasi dari samjudson 's jawaban diterima yang tidak.

public static String GetOrdinal(int i)
{
    String res = "";

    if (i > 0)
    {
        int j = (i - ((i / 100) * 100));

        if ((j == 11) || (j == 12) || (j == 13))
            res = "th";
        else
        {
            int k = i % 10;

            if (k == 1)
                res = "st";
            else if (k == 2)
                res = "nd";
            else if (k == 3)
                res = "rd";
            else
                res = "th";
        }
    }

    return i.ToString() + res;
}

Juga Shahzad Qureshi 's jawabannya menggunakan manipulasi string bekerja dengan baik, namun hal itu memiliki hukuman kinerja. Untuk menghasilkan banyak dari ini, program contoh LINQPad membuat versi string 6-7 kali lebih lambat daripada yang integer ini (meskipun Anda harus menghasilkan banyak untuk memperhatikan).

Contoh LINQPad:

void Main()
{
    "Examples:".Dump();

    foreach(int i in new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 22, 113, 122, 201, 202, 211, 212, 2013, 1000003, 10000013 })
        Stuff.GetOrdinal(i).Dump();

    String s;

    System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();

    for(int iter = 0; iter < 100000; iter++)
        foreach(int i in new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 22, 113, 122, 201, 202, 211, 212, 2013, 1000003, 1000013 })
            s = Stuff.GetOrdinal(i);

    "Integer manipulation".Dump();
    sw.Elapsed.Dump();

    sw.Restart();

    for(int iter = 0; iter < 100000; iter++)
        foreach(int i in new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 22, 113, 122, 201, 202, 211, 212, 2013, 1000003, 1000013 })
            s = (i.ToString() + Stuff.GetOrdinalSuffix(i));

    "String manipulation".Dump();
    sw.Elapsed.Dump();
}

public class Stuff
{
        // Use integer manipulation
        public static String GetOrdinal(int i)
        {
                String res = "";

                if (i > 0)
                {
                        int j = (i - ((i / 100) * 100));

                        if ((j == 11) || (j == 12) || (j == 13))
                                res = "th";
                        else
                        {
                                int k = i % 10;

                                if (k == 1)
                                        res = "st";
                                else if (k == 2)
                                        res = "nd";
                                else if (k == 3)
                                        res = "rd";
                                else
                                        res = "th";
                        }
                }

                return i.ToString() + res;
        }

        // Use string manipulation
        public static string GetOrdinalSuffix(int num)
        {
                if (num.ToString().EndsWith("11")) return "th";
                if (num.ToString().EndsWith("12")) return "th";
                if (num.ToString().EndsWith("13")) return "th";
                if (num.ToString().EndsWith("1")) return "st";
                if (num.ToString().EndsWith("2")) return "nd";
                if (num.ToString().EndsWith("3")) return "rd";
                return "th";
        }
}

Saya tidak dapat menemukan komentar @ nickf, apa yang salah dengan jawaban samjudson? Sepertinya saya suka menangani angka di atas 1000 dengan baik sementara jauh lebih mudah dibaca daripada milik Anda.
Joshua Walsh

1
Itu komentar yang adil, saya baru saja menjalankan set tes dan saya tidak dapat menemukan masalah. Sepertinya tidak ada perubahan pada jawaban Sam juga jadi aku hanya bisa membayangkan aku menjadi gila. Saya telah mengedit jawaban saya untuk mencerminkan hal itu.
Whelkaholism

1
Haha, kita semua memiliki momen seperti itu bukan? Kami melihat kembali kode lama dan berkata "mengapa saya menulis ini?"
Joshua Walsh

1

Berdasarkan dari jawaban lain:

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

3
TEMPAT 1: Jawaban Tidak Jelas Yang Paling Tidak Perlu. "Tidak Perlu": Ukuran kode / manfaat kinerja tidak sebanding dengan biaya keterbacaan. "Cryptic": Terjemahan signifikan diperlukan untuk memetakan ke Persyaratan "Awam".
Tom

0

FWIW, untuk MS-SQL, ungkapan ini akan melakukan pekerjaan. Simpan WHEN pertama ( WHEN num % 100 IN (11, 12, 13) THEN 'th') sebagai yang pertama dalam daftar, karena ini bergantung pada dicoba sebelum yang lain.

CASE
  WHEN num % 100 IN (11, 12, 13) THEN 'th' -- must be tried first
  WHEN num % 10 = 1 THEN 'st'
  WHEN num % 10 = 2 THEN 'nd'
  WHEN num % 10 = 3 THEN 'rd'
  ELSE 'th'
END AS Ordinal

Untuk Excel:

=MID("thstndrdth",MIN(9,2*RIGHT(A1)*(MOD(A1-11,100)>2)+1),2)

Ekspresi (MOD(A1-11,100)>2)ini BENAR (1) untuk semua angka kecuali yang diakhiri dengan 11,12,13(FALSE = 0). Jadi 2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1)berakhir sebagai 1 untuk 11/12/13, jika tidak:
1 mengevaluasi ke 3
2 hingga 5,
3 hingga 7
lainnya: 9
- dan 2 karakter yang diperlukan dipilih dari "thstndrdth"mulai dari posisi itu.

Jika Anda benar-benar ingin mengonversi itu secara langsung ke SQL, ini berhasil bagi saya untuk beberapa nilai pengujian:

DECLARE @n as int
SET @n=13
SELECT SubString(  'thstndrdth'
                 , (SELECT MIN(value) FROM
                     (SELECT 9 as value UNION
                      SELECT 1+ (2* (ABS(@n) % 10)  *  CASE WHEN ((ABS(@n)+89) % 100)>2 THEN 1 ELSE 0 END)
                     ) AS Mins
                   )
                 , 2
                )

0

Ini adalah implementasi dartdan dapat dimodifikasi sesuai dengan bahasa.

String getOrdinalSuffix(int num){
    if (num.toString().endsWith("11")) return "th";
    if (num.toString().endsWith("12")) return "th";
    if (num.toString().endsWith("13")) return "th";
    if (num.toString().endsWith("1")) return "st";
    if (num.toString().endsWith("2")) return "nd";
    if (num.toString().endsWith("3")) return "rd";
    return "th";
}

0

Meskipun ada banyak jawaban bagus di sini, saya kira ada ruang untuk yang lain, kali ini berdasarkan pencocokan pola, jika tidak untuk hal lain, maka setidaknya untuk keterbacaan yang dapat diperdebatkan

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

dan apa yang membuat solusi ini istimewa? hanya fakta bahwa saya menambahkan beberapa pertimbangan kinerja untuk berbagai solusi lainnya

terus terang saya meragukan kinerja benar-benar penting untuk skenario khusus ini (yang benar-benar membutuhkan tata cara jutaan angka) tetapi setidaknya muncul beberapa perbandingan untuk diperhitungkan ...

1 juta item untuk referensi (millage Anda mungkin bervariasi berdasarkan spesifikasi mesin tentunya)

dengan pencocokan pola dan pembagian (jawaban ini)

~ 622 ms

dengan pencocokan pola dan string (jawaban ini)

~ 1967 ms

dengan dua sakelar dan divisi (jawaban yang diterima)

~ 637 ms

dengan satu saklar dan divisi (jawaban lain)

~ 725 ms

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

0

Satu-liner lain, tetapi tanpa perbandingan dengan hanya mengindeks hasil regex ke dalam array.

public static string GetOrdinalSuffix(int input)
{
    return new []{"th", "st", "nd", "rd"}[Convert.ToInt32("0" + Regex.Match(input.ToString(), "(?<!1)[1-3]$").Value)];
}

Versi PowerShell dapat dipersingkat lebih lanjut:

function ord($num) { return ('th','st','nd','rd')[[int]($num -match '(?<!1)[1-3]$') * $matches[0]] }

0

1 liner lagi.

public static string Ordinal(this int n)
{    
 return n + (new [] {"st","nd","rd" }.ElementAtOrDefault((((n + 90) % 100 - 10) % 10 - 1)) ?? "th");
}

-2

Ini adalah kelas Extension DateTime. Salin, Tempel & Nikmati

DateTimeExtensions kelas publik statis {

    public static string ToStringWithOrdinal(this DateTime d)
    {
        var result = "";
        bool bReturn = false;            

        switch (d.Day % 100)
        {
            case 11:
            case 12:
            case 13:
                result = d.ToString("dd'th' MMMM yyyy");
                bReturn = true;
                break;
        }

        if (!bReturn)
        {
            switch (d.Day % 10)
            {
                case 1:
                    result = d.ToString("dd'st' MMMM yyyy");
                    break;
                case 2:
                    result = d.ToString("dd'nd' MMMM yyyy");
                    break;
                case 3:
                    result = d.ToString("dd'rd' MMMM yyyy");
                    break;
                default:
                    result = d.ToString("dd'th' MMMM yyyy");
                    break;
            }

        }

        if (result.StartsWith("0")) result = result.Substring(1);
        return result;
    }
}

Hasil:

9 Oktober 2014


Anda menduplikasi: a) String Format Tanggal (X5) dan b) seluruh sisa Metode (ketika Case Use muncul (jika belum) bahwa akhiran ordinal diperlukan untuk non-Hari Bulan. tujuan atau bahkan Hari Bulan dengan String Format Tanggal yang berbeda). Gunakan Metode "OrdinalSuffix" yang saya sarankan untuk diekspos dari jawaban Ian Warburton pada 6 April 17 jam 16:32 ( stackoverflow.com/questions/20156/… ).
Tom

-3

Alternatif lain yang saya gunakan berdasarkan semua saran lain, tetapi tidak memerlukan casing khusus:

    public static string DateSuffix(int day)
    {
        if (day == 11 | day == 12 | day == 13) return "th";
        Math.DivRem(day, 10, out day);
        switch (day)
        {
            case 1:
                return "st";
            case 2:
                return "nd";
            case 3:
                return "rd";
            default:
                return "th";
        }
    }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.