Есть ли простой способ создания ординалов в C #? - PullRequest
188 голосов
/ 21 августа 2008

Есть ли в C # простой способ создания ординалов для числа? Например:

  • 1 возвращает 1-е
  • 2 возвращает 2-е
  • 3 возвращает 3-е
  • ... и т.д.

Можно ли это сделать с помощью String.Format() или для этого есть какие-либо функции?

Ответы [ 17 ]

2 голосов
/ 06 апреля 2017

Запрошенная версия ответа Самджудсона с "меньшей избыточностью" ...

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);
}
1 голос
/ 16 декабря 2014

РЕДАКТИРОВАТЬ : Как указывает YM_Industries в комментарии, ответ Самджудсона ДЕЙСТВИТЕЛЬНО работает с числами свыше 1000, комментарий Никфа, похоже, исчез, и я не могу вспомнить, в чем проблема Я видел был. Оставьте здесь этот ответ для сравнения времени.

Очень многие из них не работают для чисел> 999, как указано в комментарии nickf (ПРАВКА: теперь отсутствует).

Вот версия, основанная на модифицированной версии samjudson принятый ответ , что делает.

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

Также Shahzad Qureshi ' answer , использующий манипуляции со строками, работает нормально, однако он имеет снижение производительности. Для генерации многих из них пример программы LINQPad делает строковую версию в 6-7 раз медленнее, чем эта целочисленная (хотя вам придется генерировать много, чтобы заметить).

Пример 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";
        }
}
0 голосов
/ 09 октября 2014

Вот класс Расширения DateTime. Скопируйте, вставьте и наслаждайтесь

открытый статический класс DateTimeExtensions {

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

Результат:

9 октября 2014

0 голосов
/ 19 сентября 2014

FWIW, для MS-SQL это выражение сделает работу. Оставьте первое КОГДА (WHEN num % 100 IN (11, 12, 13) THEN 'th') первым в списке, поскольку это зависит от того, будут ли судить другие.

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

Для Excel:

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

Выражение (MOD(A1-11,100)>2) равно TRUE (1) для всех чисел, кроме любого, заканчивающегося 11,12,13 (FALSE = 0). Таким образом, 2 * RIGHT(A1) * (MOD(A1-11,100)>2) +1) заканчивается как 1 для 11/12/13, в противном случае:
1 оценивает до 3
От 2 до 5
От 3 до 7
другие: 9
- и необходимые 2 символа выбираются из "thstndrdth", начиная с этой позиции.

Если вы действительно хотите преобразовать это непосредственно в SQL, у меня получилось несколько тестовых значений:

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 голосов
/ 16 декабря 2013
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";
}
0 голосов
/ 16 мая 2017

Исходя из других ответов:

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";                                              
}
0 голосов
/ 23 февраля 2014

Другая альтернатива, которую я использовал, основана на всех других предложениях, но не требует специального корпуса:

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