Напишите функцию плюрализации для русского языка

25

В английском языке существительные могут принимать две разные формы в зависимости от того, являются ли они единственными (одним) или множественным числом (что-либо еще). Например, мы бы сказали «1 собака», но «2 собаки», «0 собак», «57 собак» и так далее.

На русском языке есть три категории. Вместо «1 собака, 2 собаки, 5 собак» на русском языке это будет «1 собака, 2 собаки, 5 собак».

Категории делятся по следующей логике:

  • «Singular»: используется для 1 и любого числа, заканчивающегося на 1, за исключением чисел, заканчивающихся на 11.
    • Примеры: 1 собака, 21 собака, 101 собака
  • «Несколько»: используется для 2, 3 и 4, а также для любого числа, оканчивающегося на 2, 3 или 4, за исключением чисел, оканчивающихся на 12, 13 и 14.
    • Примеры: 2 собаки, 3 собаки, 4 собаки, 32 собаки, 43 собаки, 104 собаки
  • «Многие»: все, что не считается «Единственным» или «Мало».
    • Примеры: 0 собак, 5 собак, 11 собак, 13 собак, 25 собак, 111 собак, 114 собак

Соревнование

Если задан целочисленный ввод в диапазоне [0, 1000], верните, 1если он принадлежит категории «единственное число», 2если он принадлежит категории «несколько» и 5если он принадлежит категории «многие».

Ваша программа может быть функцией или может использовать STDIN. Вы можете распечатать в STDOUT или вернуть значение из функции

Это сложная задача для гольфа , поэтому выигрывает решение с наименьшим количеством байтов.

Питер Олсон
источник
2
@ Phoenix Не на русском языке.
Питер Олсон,
2
Почему 1, 2и 5в частности? Кроме того, почему я не могу использовать коды выхода?
CalculatorFeline
6
@ Phoenix Это звучит так совершенно неправильно для меня - ломаный русский - я всегда использовал форму в вопросе, и я нахожу ее правильной, и, видимо, это так
dkudriavtsev
2
@CalculatorFeline Если вы начинаете считать с 1, вы получаете единственное число в 1, немногие сначала появляются в 2, многие сначала появляются в 5. Имеет смысл :-)
LLlAMnYP
5
Считать по-русски крайне сложно. Возможно, стоит отметить, что последняя цифра определяет случай . 1 = именительный падеж единственного числа 2,3,4 = родительный падеж единственного числа, 5-0 родительный падеж множественного числа. Это меняется в зависимости от случая фразы, и так как есть 6 случаев, есть 24 формы «один» (который является мужским), 24 формы «два» (который является женским) и так далее. Говорят, что профессор русского языка в моем местном университете вряд ли сможет перевести « с 2345 собаками», потому что «с» требует инструментального случая (тяжелый).
smirkingman

Ответы:

15

Python 2 , 36 байт

lambda n:'5521'[n%~9/-3>>n/10%~9/-9]

Попробуйте онлайн!

Та же длина арифметически:

lambda n:5/(n%~9/-3>>n/10%~9/-9or 1)

Давайте сначала посмотрим на более простой код, который не учитывает подростков.

lambda n:'5521'[n%~9/-3]

Здесь мы хотим отобразить одну цифру на выход, который работает как

[5, 1, 2, 2, 2, 5, 5, 5, 5, 5][n%10]

Но вместо того, чтобы взять nпо модулю 10 ( %10), мы можем сделать n%-10, что сопоставляется с интервалами, [-9..0]чтобы дать остатки:

> [n%~9 for n in range(10)]
[0, -9, -8, -7, -6, -5, -4, -3, -2, -1]

Это многообещающе, потому что первые две записи 0и -9находятся далеко друг от друга, и их нужно отправлять на разные выходы. Также -10можно сократить до ~9.

Отсюда деление на этаж /-3дает куски по 3 с правильной стартовой точкой

> [n%~9/-3 for n in range(10)]
[0, 3, 2, 2, 2, 1, 1, 1, 0, 0]

Чтобы получить желаемый результат, нам просто нужно отобразить 0->5, 1->5, 2->2, 1->1, что мы делаем с выбором строки '5521'[_].

Теперь нам также нужны числа, заканчивающиеся на 11-15, чтобы всегда давать 5. Сначала мы делаем это, определяя, является ли цифра десятками 1. Принимая n/10для удаления последнюю цифру, мы применяем, %~9как и прежде, чтобы получить результаты

[0, -9, -8, -7, -6, -5, -4, -3, -2, -1]

для соответствующих окончательных цифр. Цифра 1, которую мы хотим обнаружить, сопоставляется с экстремальным значением -9. Этаж делится -9на 1, а все остальное на 0.

> [k%~9/-9 for k in range(10)]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]

Наконец, мы делаем так, чтобы этот индикатор 1всегда выдавал выход 5. Это делается путем сдвига битового результата n%~9/-3вправо на индикатор. Результат 0,1,2,3всегда сдвигает бит вправо на 0 или 1, что дает желаемый результат 5.

XNOR
источник
7
Пожалуйста, объясни.
CalculatorFeline
12

Python 2 , 45 байт

lambda n,s='5122255555':(s+'5'*10+s*8)[n%100]

Попробуйте онлайн!

прут
источник
о_О я
сдулся
Кроме того, не (s+'5'*10+s*9)110 символов?
CalculatorFeline
@CalculatorFeline хм, пора выпить кофе @. @
Род
5
@ Род или подушка?
Ник Т
8

Perl 5 , 26 байт

25 байт кода + -pфлаг.

$_=/1.$|[5-90]$/?5:2-/1$/

Попробуйте онлайн!

Для еще одного байта, есть $_=/(?<!1)[1-4]$/?2-/1$/:5.

Пояснения: (в 27-байтовой версии; 26 довольно симметрична)
И «единственное число», и «несколько» заканчиваются «не 1, за которым следует цифра от 1 до 4» (проверено с помощью (?<!1)[1-4]$/). В этом случае результат равен 2 минус 1, если число заканчивается на 1 ( 2-/1$/). В противном случае результат, если 5.

папа
источник
5
Perl превосходит 05AB1E по справедливости.
Эрик Outgolfer
7

JavaScript (ES6), 53 49 48 40 39 38 37 36 байт

n=>/[05-9]$|1.$/.test(n)?5:1+(n%5>1)

Попытайся

f=
n=>/[05-9]$|1.$/.test(n)?5:1+(n%5>1)
oninput=_=>o.innerText=f(+i.value);o.innerText=f(i.value=0)
<input id=i type=number><pre id=o>

мохнатый
источник
1[1-4]может быть 1.и /1$/.test(s)может быть +s%10==1. Никогда не забудь одинарную +!
CalculatorFeline
Спасибо, @CalculatorFeline - хорошо заметен на первом :)
Shaggy
Я не думаю, что вам нужен унарный +вообще, s%10следует преобразовать sв число.
ETHproductions
Да, только что понял это, @ETHproductions.
Лохматый
1
n%10-> n%5сохраняет байт
Йохан Карлссон
4

Желе ,  19  18 байт

DµṖṚi1’ȧṪị“M;ọ6’D¤

Монадическая ссылка, принимающая и возвращающая неотрицательные целые числа.

Попробуйте онлайн! или посмотрите три группы от 0 до 1000 включительно в этом наборе тестов .

Как?

DµṖṚi1’ȧṪị“M;ọ6’D¤ - Main link: non-negative number, n  e.g. 301      311      313
D                  - cast to decimal list                [3,0,1]  [3,1,1]  [1,3,3]
 µ                 - monadic chain separation, call that d
  Ṗ                - pop d                               [3,0]      [3,1]    [1,3]
   Ṛ               - reverse                             [0,3]      [1,3]    [3,1]
     1             - literal 1
    i              - first index of (0 if not found)      0          1        2      
      ’            - decrement                           -1          0        1
        Ṫ          - tail d                               1          1        3
       ȧ           - logical and                          1          0        3
                 ¤ - nilad followed by link(s) as a nilad:
          “M;ọ6’   -   base 250 literal = 1222555555
                D  -   cast to decimal list [1,2,2,2,5,5,5,5,5,5]
         ị         - index into (1-based and modular)     1          5        2
Джонатан Аллан
источник
1
Пояснения пожалуйста.
CalculatorFeline
@CalculatorFeline все еще работает над игрой в гольф ...
Джонатан Аллан
@CalculatorFeline хорошо, я не могу найти лучше; объяснение добавлено.
Джонатан Аллан
В какой кодировке эти 18 символов могут быть представлены 18 байтами?
exebook
@exebook Jelly использует свою собственную кодовую страницу
GamrCorps
3

05AB1E , 38 19 байт

Использует трюк с индексом из ответа Питона Рода

•1rꢰ•©5T×®9×JIт%è

Попробуйте онлайн!

объяснение

•1rꢰ•              # push the number 5122255555
       ©             # store a copy in register
        5T×          # push 5 repeated 10 times
           ®         # retrieve the first number from register
            9×       # repeat it 9 times
              J      # join everything to string
               Iт%   # push input mod 100
                  è  # use this to index into the string of digits
Emigna
источник
8
Вы проигрываете Perl, я думаю, что-то здесь не так.
Павел
@ Феникс: Да. Либо эта задача хорошо подходит для регулярных выражений, либо я делаю что-то ужасно неправильное :) Честно говоря, Perl часто играет в гольф.
Эминья,
4
@ Enigma ... и игроки в Perl часто очень хороши, верно? ;-)
Дада
@ Дада: очень верно!
Эминья,
Пояснения пожалуйста.
CalculatorFeline
2

PHP> = 7.1, 44 байта

<?=$argn[-2]!=1&($m=($argn+9)%10)<4?2-!$m:5;

Онлайн версия

Йорг Хюльсерманн
источник
1
3 байт короче: <?=$argn[-2]!=1&($m=($argn+9)%10)<4?2-!$m:5;.
user63956
2

Сборка MCxxxx , 123 байта

e:slx x0
mov x0 acc
dst 2 0
tlt acc 11
-tgt acc 14
-jmp v
+dgt 0
teq acc 1
+mov 1 x1
+jmp e
tlt acc 5
+mov 2 x1
v:-mov 5 x1

Заметка:

TiO не поддерживает этот язык, который используется в игре Zachtronics Shenzhen I / O , поэтому нет ссылки для проверки этого.

Объяснение:

Эта функция принимает вход через порт XBus x0 и выводит через порт x1. Это слишком долго для выполнения на MC4000, но хорошо вписывается в память MC6000. Порты XBus для тех, кто не знаком, позволяют передавать дискретные пакеты цифровых данных.

Одна часть информации, которая может быть полезна при чтении этого: в сборке MCxxxx инструкции по тестированию устанавливают флаг, который указывает, какую ветвь следует взять. Строки, начинающиеся с, +выполняются только в том случае, если последний тест вернул значение true, а строки, начинающиеся с, -выполняются только в том случае, если тест был ложным.

Построчно:

e:slx x0    # Label this line e, then sleep until input is available on XBus port x0
mov x0 acc  # Move the input into register acc 
dst 2 0     # Set the leftmost digit of the input to 0
tlt acc 11  # Test if the value in acc is less than 11
-tgt acc 14 # If it's not, check if it's greater than 14
-jmp v      # If it's not, jump to the line labeled v (the last line)
+dgt 0      # If either of the previous tests returned true,
            #     set acc to the value of acc's rightmost digit
teq acc 1   # Test if acc equals 1
+mov 1 x1   # If it does, return 1
+jmp e      # Then jump to label e, which ends execution
tlt acc 5   # Test if acc is less than 5
+mov 2 x1   # If it is, return 2
v:-mov 5 x1 # If the previous test is false, return 5

Замечание по поводу оценки: сборка MCxxxx сама по себе не имеет функций, но она настолько близка к функции, насколько вы можете ее получить - это программа, которая помещается в один исполнительный узел, принимает входные данные через один порт и выводит через другой. В результате я оценил это как функцию (т.е. без подсчета байтов, необходимых для создания действительного файла эмулятора MCxxxx).

Tutleman
источник
1

Haskell , 62 58 байт

f n|s<-"5122255555"=(s++('5'<$[0..9])++cycle s)!!mod n 100

Попробуйте онлайн!

объяснение

Это создает следующую строку:

5122255555555555555551222555555122255555512225555551222555555122255555512225555551222555555122255555 ...

Который является таблицей, где ячейка nсодержит ответ для nthчисла. Таблица верна только для первых 100 элементов, следовательно mod.

bartavelle
источник
Можете ли вы объяснить, что здесь происходит? Вы можете наверняка сократить его, используяf n|s<-"5122255555"=(s++('5'<$[0..9])++cycle s)!!mod n 100
flawr
Я не знал, что это возможно!
Bartavelle
1
В codegolf.stackexchange.com/questions/19255/ много других советов и хитростей действительно стоит прочитать =)
flawr
0

Скала, 110 байт

n=>Stream.iterate("512225555555555555555")(_=>"1222555555").flatMap(_.toCharArray).map(_.toInt).take(n-1).head
Феникс
источник
0

Turtlèd, 35 байт

!--.(1#0#)+.@3(1@1)(2@2)(3@2)(4@2),

Попробуйте онлайн!

Эта функция требует, чтобы ввод начинался с>, что, я думаю, нормально, потому что python2 использует ввод наполовину регулярно, и для этого нужны кавычки.

Объяснение:

!             input the number as a string, complete with the >
 --.          wrap around to the end of the string, and then move one back. if this
              is a single digit, we end up on the >,
              otherwise we end up on the second to last digit. write the digit/>

    (1#0#)    if it is 1, set the string to 0. this way it will always write 3 at the end.



          +.       write the last digit (or 0 if the second last digit was 1)
            @3      set the character variable to 3. this means if what was written was not
                       in (1, 2, 3, 4), then it will write 3 at the end
              (1@1)    if the character written was a 1, set the character to be written
                       at the end to 1
                   (2@2)(3@2)(4@2)
                     if it is any of 2,3,4, set the character to be written at the end to 2
                                  ,    write the character that was set
Разрушаемый Лимон
источник
>Служит ли это цели в Turtled или это произвольный символ, который вы добавили к вводу?
Лохматый