Escribe una función de pluralización para ruso


25

En inglés, los sustantivos pueden tomar dos formas diferentes dependiendo de si son singulares (uno) o plurales (cualquier otra cosa). Por ejemplo, diríamos "1 perro" pero "2 perros", "0 perros", "57 perros", etc.

En ruso, hay tres categorías. En lugar de "1 perro, 2 perros, 5 perros", en ruso sería "1 собака, 2 собаки, 5 собак".

Las categorías se dividen según la siguiente lógica:

  • "Singular": se usa para 1 y cualquier número que termine en 1, excepto los números que terminan en 11.
    • Ejemplos: 1 собака, 21 собака, 101 собака
  • "Pocos": se usa para 2, 3 y 4, y cualquier número que termine en 2, 3 o 4, excepto los números que terminan en 12, 13 y 14.
    • Ejemplos: 2 собаки, 3 собаки, 4 собаки, 32 собаки, 43 собаки, 104 собаки
  • "Muchos": cualquier cosa que no se considere "Singular" o "Pocos".
    • Ejemplos: 0 собак, 5 собак, 11 собак, 13 собак, 25 собак, 111 собак, 114 собак

El reto

Dada una entrada entera en el rango [0, 1000], devuelve 1si pertenece a la categoría "singular", 2si pertenece a la categoría "pocos" y 5si pertenece a la categoría "muchos".

Su programa puede ser una función o puede usar STDIN. Puede imprimir en STDOUT o devolver un valor de la función

Este es un desafío de código de golf , por lo que gana la solución con el menor número de bytes.



2
¿Por qué 1, 2y 5en particular? Además, ¿por qué no puedo usar códigos de salida?
CalculatorFeline

66
@ Phoenix Eso me suena completamente mal - ruso roto - Siempre he usado el formulario en la pregunta y me parece correcto, y aparentemente lo es
dkudriavtsev

2
@CalculatorFeline Si comienzas a contar desde 1, obtienes singular en 1, pocos aparecen primero en 2, muchos aparecen primero en 5. Tiene perfecto sentido :-)
LLlAMnYP

55
Contar en ruso es extremadamente difícil. Quizás valga la pena señalar que el último dígito determina el caso . 1 = Nominativo singular 2,3,4 = Genitivo singular, 5-0 Genitivo plural. Esto cambia con el caso de la frase, y como hay 6 casos, hay 24 formas de 'uno' (que es masculino), 24 formas de 'dos' (que es femenino) y así sucesivamente. Se dice que sería improbable que el profesor de ruso en mi universidad local pudiera traducir " con 2345 perros", porque 'con' exige el caso instrumental (difícil).
smirkingman

Respuestas:


15

Python 2 , 36 bytes

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

Pruébalo en línea!

Misma longitud aritméticamente:

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

Primero veamos un código más simple que no tiene en cuenta a los adolescentes.

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

Aquí, queremos un mapeo del dígito de uno a una salida que funcione como

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

Pero, en lugar de tomar el nmódulo 10 ( %10), podemos hacer n%-10, que se asigna a los intervalos [-9..0]para dar restos:

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

Esto es prometedor porque las dos primeras entradas 0y -9están muy separadas, y deben enviarse a diferentes salidas. Además, -10se puede acortar a ~9.

A partir de aquí, dividir el piso por /-3trozos de 3 con el punto de partida correcto

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

Para obtener el resultado deseado, ahora solo necesitamos asignar 0->5, 1->5, 2->2, 1->1, lo que hacemos con la selección de cadena '5521'[_].

Ahora, también necesitamos números que terminen en 11 a 15 para dar siempre 5. Primero hacemos esto detectando si entonces diez dígitos es 1. Tomando n/10para eliminar el último dígito, luego aplicamos %~9como antes para obtener los resultados

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

para los respectivos dígitos finales. El dígito de 1 que queremos detectar se asigna al valor extremo -9. Al dividir el piso se -9convierte en 1 y todo lo demás en 0.

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

Finalmente, hacemos que este indicador 1siempre dé la salida 5. Esto se hace cambiando ligeramente el resultado de la n%~9/-3derecha por el indicador. El resultado de 0,1,2,3los cambios de bits siempre a la derecha a 0 o 1, lo que da una salida de 5 como se desee.


77
Por favor explique.
CalculatorFeline


8

Perl 5 , 26 bytes

25 bytes de código + -pbandera.

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

Pruébalo en línea!

Para un byte más, hay $_=/(?<!1)[1-4]$/?2-/1$/:5.

Explicaciones: (en la versión de 27 bytes; el 26 es bastante simétrico)
Tanto "singular" como "pocos" terminan con "no un 1 seguido de un dígito de 1 a 4" (probado con (?<!1)[1-4]$/). En esos casos, el resultado es 2, menos 1 si el número termina con 1 ( 2-/1$/). De lo contrario, el resultado es 5.


55
tfw Perl supera a 05AB1E por una buena cantidad.
Erik the Outgolfer

7

JavaScript (ES6), 53 49 48 40 39 38 37 36 bytes

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

Intentalo

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]puede ser 1.y /1$/.test(s)podría ser +s%10==1. Nunca olvides unario +!
CalculatorFeline

Gracias, @CalculatorFeline - bien visto en el primero :)
Shaggy

No creo que necesite el unario +en absoluto, s%10debería convertirlo sen un número.
ETHproductions

Sí, también me di cuenta de eso, @ETHproductions.
Shaggy

1
n%10-> n%5guarda un byte
Johan Karlsson

4

Jalea ,  19  18 bytes

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

Un enlace monádico que toma y devuelve enteros no negativos.

Pruébalo en línea! o vea los tres grupos de 0 a 1000 inclusive en este conjunto de pruebas .

¿Cómo?

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
Explicación por favor.
CalculatorFeline

@CalculatorFeline sigue trabajando en el golf ...
Jonathan Allan

@CalculatorFeline bien, no puedo encontrar nada mejor; explicación agregada.
Jonathan Allan

¿En qué codificación de caracteres esos 18 caracteres se pueden representar con 18 bytes?
exebook

@exebook Jelly usa su propia página de códigos
GamrCorps

3

05AB1E , 38 19 bytes

Utiliza el truco del índice de la respuesta de Python de Rod

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

Pruébalo en línea!

Explicación

•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

8
Estás perdiendo contra Perl, creo que algo está mal aquí.
Pavel

@ Phoenix: Sí. O este desafío es adecuado para expresiones regulares o estoy haciendo algo terriblemente mal :) Para ser justos, Perl a menudo es bastante golfista.
Emigna

44
@Enigma ... y los golfistas de Perl a menudo son muy buenos, ¿verdad? ;-)
Dada

@Dada: ¡Muy cierto!
Emigna

Explicación por favor.
CalculatorFeline


2

Conjunto MCxxxx , 123 bytes

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

Nota:

TiO no admite este lenguaje, que se usa en el juego Zachtronics Shenzhen I / O , por lo que no hay un enlace para probar esto.

Explicación:

Esta es una función que toma entrada a través del puerto XBus x0 y sale a través del puerto x1. Es demasiado largo para ejecutarse en un MC4000, pero encaja perfectamente en la memoria de un MC6000. Los puertos XBus, para aquellos que no están familiarizados, permiten la transmisión de paquetes discretos de datos digitales.

Una pieza de información que puede ser útil para leer esto: en el ensamblaje MCxxxx, las instrucciones de prueba establecen una bandera que indica qué rama se debe tomar. Las líneas que comienzan +solo se ejecutan si la prueba más reciente devuelve verdadero, y las líneas que comienzan -solo se ejecutan si la prueba fue falsa.

Linea por linea:

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

Una nota sobre la puntuación: el ensamblaje MCxxxx no tiene funciones per se, pero es lo más parecido a una función que pueda obtener: es un programa que cabe en un solo nodo de ejecución, toma la entrada a través de un puerto y las salidas a través de otro. Como resultado, he calificado esto como una función (es decir, sin contar los bytes necesarios para crear un archivo de emulador MCxxxx válido).



1

Haskell , 62 58 bytes

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

Pruébalo en línea!

Explicación

Esto construye la siguiente cadena:

5122255555555555555551222555555122255555512225555551222555555122255555512225555551222555555122255555 ...

Cuál es una tabla donde la celda ncontiene la respuesta para el nthnúmero. La tabla solo es correcta para los primeros 100 elementos, de ahí el mod.


¿Puedes explicar lo que está pasando aquí? Seguramente podría reducir su longitud usandof n|s<-"5122255555"=(s++('5'<$[0..9])++cycle s)!!mod n 100
flawr

¡No sabía que eso fuera posible!
bartavelle

1
Hay muchos más consejos y trucos en codegolf.stackexchange.com/questions/19255/… realmente vale la pena leer =)
error

0

Scala, 110 bytes

n=>Stream.iterate("512225555555555555555")(_=>"1222555555").flatMap(_.toCharArray).map(_.toInt).take(n-1).head

0

Turtlèd, 35 bytes

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

Pruébalo en línea!

Esta función requiere que la entrada comience con un>, lo que supongo que está bien porque python2 usa la entrada semi regularmente, y eso necesita comillas.

Explicación:

!             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

¿Tiene >algún propósito en Turtled o es un personaje arbitrario que has agregado a la entrada?
Shaggy
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.