Ensamblar automáticamente un aria aliterativa de forma predecible

15

Gracias a @ComradeSparklePony por el título.

Este desafío debería ser muy simple. Te dan tres listas.

El primero es una lista de nombres, en caso de título.

El segundo es una lista de adjetivos, en minúsculas.

El tercero es una lista de sustantivos, en minúsculas.

Seleccione al azar un nombre, adjetivo opcional, nombre y salida <Name>'s <adjective> <noun>. Sin embargo, cada palabra debe comenzar con la misma letra. Puede suponer que todas las palabras comienzan con una letra. También puede suponer (pero tenga en cuenta en su respuesta si lo hace):

  • que todas las palabras están compuestas únicamente por caracteres alfabéticos
  • que hay al menos un sustantivo para cada nombre
  • que hay al menos un nombre para cada sustantivo

Sin embargo, no puede suponer que existe un adjetivo para un par particular de nombre y nombre, ya que el adjetivo es opcional, por lo que la salida seguirá siendo válida.

No tiene que seleccionar la letra compartida de manera uniforme, aunque todas las letras disponibles deben tener una probabilidad distinta de cero. Sin embargo, debe asegurarse de que todas las salidas para una letra dada tengan la misma probabilidad de ocurrir dentro de los límites del generador de números aleatorios de su idioma. En el caso del adjetivo, esto es equivalente a tener una entrada adicional que significa "sin adjetivo para esta letra" que tiene la misma posibilidad que todos los otros adjetivos para esa letra.

Ejemplo de listas de entrada:

Joan Neil Nicola Oswald Sherman Stephanie
new novel old original second silent
jeep noun novel output second sheep snake

Ejemplo de salidas para estas entradas (cada línea es un ejemplo separado):

Stephanie's second second
Sherman's silent snake
Oswald's original output
Nicola's novel novel
Neil's noun
Joan's jeep

Tenga en cuenta que no hay espacio adicional entre las palabras en los últimos dos ejemplos.

Este es el , por lo que gana el código más corto que no rompa ninguna laguna estándar

En el improbable caso de que ayude, puede ingresar todo en mayúsculas, pero aún necesita emitir en mayúsculas y minúsculas.

Neil
fuente
¿Es correcto suponer que el programa debería devolver: 1 nombre 1 adjetivo (si uno coincide con el nombre) 1 sustantivo? ¿O está pidiendo producir una salida para cada nombre?
DavidC
1
¿Quizás debería agregar 'Joan' y 'jeep' en su ejemplo para ilustrar el hecho de que puede no haber ningún adjetivo para una letra dada?
Arnauld
Dado su ejemplo de entrada, ¿existe la posibilidad de que no haya un adjetivo 1 en 3 (ya que todas las "listas" de adjetivos son 2 largas)? ... y si 'Joan' y 'Jeep' también estuvieran allí sin ningún jadjetivo, ¿la probabilidad sería 4 en 9? Podría valer la pena colocar probabilidades contra los resultados, o enumerar todos los resultados, ya que entiendo que no solo "todos los resultados para una letra dada ..." sino también todos los resultados distintos deberían tener la misma probabilidad (dados valores distintos dentro de cada lista).
Jonathan Allan
@DavidC Lo siento, me doy cuenta de que agregar ejemplos adicionales lo ha dejado poco claro; solo produce una línea de salida para cada invocación.
Neil
1
@JonathanAllan Agregar "Joan" y "jeep" no afectaría las posibilidades relativas de que salga el "nombre de Neil" en comparación con otras opciones que contienen "Neil" y "nombre".
Neil

Respuestas:

5

Jalea ,  27 25  24 bytes

-1 gracias a Erik the Outgolfer (usa un carácter cero en lugar de un espacio)

Ż€2¦Œpḟ€0ZḢŒuEƲƇXż“'s“”K

Un programa completo que acepta un argumento en forma de una lista con formato de Python de listas de cadenas que imprime el resultado en STDOUTt.

Pruébalo en línea!

¿Cómo?

Ż€2¦Œpḟ€0ZḢŒuEƲƇXż“'s“”K - Main Link: list of lists of lists of characters
 € ¦                     - sparse application...
  2                      - ...to indices: [2]
Ż                        - ...action: prepend a zero (place holder for no adjective)
    Œp                   - Cartesian product (all choices, including invalid ones)
       €                 - for each:
      ḟ 0                -   filter out any zeros
               Ƈ         - filter keep those for which:
              Ʋ          -   last four links as a monad:
         Z               -     transpose
          Ḣ              -     head
           Œu            -     upper-case
             E           -     all equal?
                X        - random (uniform) choice  e.g. [['B','o','b'],['b','l','u','e'],['b','a','g']]
                 ż       - zip with:
                  “'s“”  -   list [["'", 's'], []]       [[['B','o','b'],["'", 's']],[['b','l','u','e'],[]],['b','a','g']]
                       K - join with spaces              [['B','o','b'],["'", 's'],' ',['b','l','u','e'],[],' ','b','a','g']
                         - implicit (smashing) print     Bob's blue bag
Jonathan Allan
fuente
24 bytes .
Erik the Outgolfer
Ah sí, agradable :)
Jonathan Allan
5

05AB1E ,  24 23  21 bytes

Asume que hay un nombre para cada nombre, según lo permitido por el desafío.

„'s«I¯ªâI‘ʒl€нË}Ωðý

Pruébalo en línea!

Explicación

„'s«                    # append "'s" to all names in the name-list
    I¯ª                 # append an empty list to the adjective-list
       â                # cartesian product between the lists
        Iâ              # cartesian product with the noun-list
          €˜            # deep flatten each sublist
            ʒ    }      # filter, keep only lists that when
             l          # converted to lowercase
              €н        # with only heads kept
                Ë       # have all elements equal
                  Ω     # pick a valid list uniformly at random
                   ðý   # and join by spaces
Emigna
fuente
¡Oh, ¯ªy €˜son inteligentes! Tenía una respuesta de 26 bytes, pero estaba teniendo problemas para arreglar el doble espacio cuando no hay un adjetivo ..
Kevin Cruijssen
@KevinCruijssen: Sí, esa fue la parte con la que también tuve más problemas. Me tomó un tiempo darme cuenta de que podía usar en ¯lugar de llenar con cadenas vacías que tuve que limpiar manualmente más tarde.
Emigna
4

R , 155 148 bytes

-7 bytes gracias a Giuseppe (usando *para sample)

function(x,y,z){`*`=sample
while(T)T=length(unique(c(tolower(substr(c(a<-x*1,b<-c(y,"")*1,c<-z*1),1,1)),"")))-2
paste0(a,"'s ",b,if(nchar(b))" ",c)}

Pruébalo en línea!

Utiliza el muestreo de rechazo: dibuja al azar un nombre, un adjetivo (posiblemente la cadena vacía) y un sustantivo hasta que coincidan las primeras letras. Esta condición se verifica contando si el número de elementos únicos en el vector formado por las primeras letras, más la cadena vacía, es de longitud 2; esto permite un adjetivo vacío.

Luego imprima el resultado, con un espacio adicional si el adjetivo no está vacío.

Las diferentes posibilidades que comienzan con la misma letra tienen probabilidades de ocurrencia iguales, ya que se samplebasa en la distribución uniforme. La forma más fácil de ver esto es condicionar en el caso de que el nombre y el nombre comiencen con la misma letra (lo cual está bien: si no lo hacen, lo rechazaríamos). Ahora condicione el evento que aceptamos: esto significa que dibujamos el adjetivo vacío o un adjetivo que comienza con la misma letra. Cada una de estas posibilidades todavía tiene la misma probabilidad.

105 5

Robin Ryder
fuente
¿Tiene esto la misma posibilidad de un adjetivo vacío entre sí para cualquier primera letra?
Nick Kennedy
@NickKennedy Sí, ya que se samplebasa en la distribución uniforme. La forma más fácil de ver esto es condicionar en el caso de que el nombre y el nombre comiencen con la misma letra (lo cual está bien: si no lo hacen, lo rechazaríamos). Ahora condicione el evento que aceptamos: esto significa que dibujamos el adjetivo vacío o un adjetivo que comienza con la misma letra. Cada una de estas posibilidades todavía tiene la misma probabilidad.
Robin Ryder
gracias bien explicado
Nick Kennedy
@ NickKennedy Gracias, agregaré esa explicación a la publicación junto con un enlace para verificar empíricamente que las probabilidades son iguales.
Robin Ryder
1
148 bytes
Giuseppe
3

JavaScript (ES6),  139124122  120 bytes

Ahorre 2 bytes gracias a @Neil

Toma entrada como (names,adjectives)(nouns).

(N,a)=>F=n=>/^(.)\S+( \1\S+)+$/i.test(s=(g=a=>a[Math.random()*a.length|0])(N)+"'s "+[(o=g([,...a]))&&o+' ']+g(n))?s:F(n)

Pruébalo en línea!

O verifique la distribución en 5 millones de sorteos

¿Cómo?

sol

g = a => a[Math.random() * a.length | 0]

sols

s = g(N) + "'s " +
    [(o = g([, ...a])) && o + ' '] +
    g(n)

Luego verificamos si todas las letras iniciales son idénticas con la siguiente expresión regular:

/^(.)\S+( \1\S+)+$/i

s

Arnauld
fuente
+[(o=g([,...a]))&&o+' ']+ahorra 2 bytes, creo?
Neil
@Neil Ah, sí. Buena esa.
Arnauld
3

Python 3 , 161 154 151 147 145 bytes

Gracias ArBo, EmbodimentOfIgnorance, Neil que han contribuido con 2, 3 y 4 bytes a mi primer golf! )

from random import*
c=choice
def f(N,a,n):
 s=c(N);w=s[0].lower();o=N
 while o[0]!=w:o=c(n)
 print(s+"'s",c([x+" "for x in a if x[0]==w]+[""])+o)

Pruébalo en línea! (con 500k ejecuciones)

  • Toma tres listas como entradas.

  • Asume al menos un sustantivo para cada nombre.


Mismo puntaje, más golf-y:

Python 3 , 145 bytes

from random import*
c=choice
def f(N,a,n):
 s=c(N);y=lambda p,e=[]:c([x+" "for x in p if x[0]==s[0].lower()]+e);print(s+"'s",y(a,[""])+y(n)[:-1])

Pruébalo en línea! (con 500k ejecuciones)

Es solo 140 si se permiten espacios en blanco al final (al quitar la cara cuadrada [:-1])

Nicola Sap
fuente
1
Buena primera respuesta! Puede guardar un byte en el primer bucle while: while t>""<t[0]!=w. También puede reemplazar la última línea print(s+"'s",t+(t and" ")+o)dejando caer u=la tercera línea.
ArBo
Terminé cambiando mi solución porque la anterior no se ajustaba a los requisitos
Nicola Sap
1
152 bytes (se eliminó el pie de página para que se ajuste a la URL en el comentario)
Encarnación de la ignorancia
1
Solo está usando la variable tuna vez, por lo que puede guardar 4 bytes al incluir el código. Creo que puede cambiar opara usar un patrón de código similar ty luego guardar otros 4 bytes al incluirlo también.
Neil
¡Gracias, ustedes realmente están ayudando! @Neil, no he podido refactorizar o: llego a esto: from random import* c=choice def f(N,a,n): s=c(N);y=lambda p,e=[]:c([x for x in p if x[0]==s[0].lower()]+e);print(s+"'s",y(a,[""])+y(n))( 137 ) pero agregar el espacio en blanco condicional, a través de un argumento opcional a y, me cuesta 11 bytes
Nicola Sap
0

Jalea , 28 bytes

1ịZḢXɓŒuḢ=ɗƇ€Ż€2¦X€ḟ0ż“'s“”K

Pruébalo en línea!

Escribí esto antes de ver la respuesta más corta de @ JonathanAllan, pero pensé que valía la pena publicarla, ya que utiliza un enfoque diferente. Guardado 3 bytes por la sugerencia de @ EriktheOutgolfer sobre esa respuesta.

Un programa completo que toma una lista de listas de cadenas e imprime implícitamente una aliteración seleccionada al azar. Asume al menos un sustantivo por nombre.

Nick Kennedy
fuente
0

C # (compilador interactivo de Visual C #) , 176 bytes

(a,b,c)=>(a=a[z.Next(a.Count)])+"'s "+b.Where(x=>(x[0]&95)==a[0]).Append("").OrderBy(x=>z.Next()).Last()+" "+c.OrderBy(x=>z.Next()).Last(x=>(x[0]&95)==a[0]);var z=new Random();

Pruébalo en línea!

Encarnación de la ignorancia
fuente
Puede suponer que los nombres comienzan con una letra mayúscula, por lo que puede poner en mayúscula las otras letras para la comparación, ¿qué debería ahorrarle 10 bytes?
Neil
@Neil Sí, exactamente 10 bytes :)
Encarnación de la ignorancia
0

Rojo , 179 bytes

func[a b c][random a random c
foreach k c[if k/1 = h: a/1/1 + 32[g: rejoin[sp k]]]collect/into[foreach
d b[if d/1 = h[keep rejoin[sp d]]]]e: copy[""]random e rejoin[a/1"'s"e/1 g]]

Pruébalo en línea!

Explicación:

Red[]
f: func[a b c][                     ; a function with 3 arguments
    random a                        ; shuffle the list of names in place
    random c                        ; shuffle the list of nouns in place
    foreach k c [                   ; for each item in the shuffled list of nouns
        if k/1 = h: a/1/1 + 32 [    ; check if it begins with the same lowercase letter
                                    ; as the first name in the shuffled list of names
            g: rejoin [" " k]       ; if yes, then insert a " " in front of it save it as g
        ]                           ; thus I always get the last match
    ]
    collect/into [                  ; collect in a new list e
        foreach d b [               ; all items form the adjectives list
            if d/1 = h [            ; that start with the same lowercase letter as the 1st noun
                keep rejoin [" " d] ; insert a " " in form of the adjective
            ]
        ]
    ] e: copy[""]                   ; the list initially has a single item - the empty string
   random e                         ; shuffle the extracted adjectives list
   rejoin [a/1 "'s" e/1 g]          ; return the formatted string
]
Galen Ivanov
fuente
0

Scala , 234 226 234 206 bytes

-28 debido al hecho de que pensé que tenía que aceptar StdIn, ahora es una función

def f(a:List[String],b:List[String],c:List[String])=scala.util.Random.shuffle(for(d<-a;e<-("" +: b);g<-c;if(d.head.toLower==g.head&&(e.isEmpty||e.head==g.head))) yield s"$d's $e $g".replace("  ", " ")).head

Pruébalo en línea!

Sin golf:

def f(names: List[String], adjectives: List[String], nouns: List[String]) = {
  val allPossible = for {
    name <- names
    adjective <- ("" +: adjectives) // Add the choice of no adjective
    noun <- nouns
    if (name.head.toLower == noun.head && (adjective.isEmpty || adjective.head == noun.head)) // Filter out so only matching entries remain
  } yield
    s"$name's $adjective $noun"
      .replace("  ", " ") // Get rid of artifact created by the empty adjective selection

  scala.util.Random.shuffle(allPossible.toList).head // Get a random element
}
Soren
fuente
0

Ruby , 94 bytes

->a,b,c{"#{n=a.sample}'s #{s=[p,*b.grep(r=/^#{n[0]}/i)].sample;s+" "if s}#{c.grep(r).sample}"}

Pruébalo en línea!

Tinta de valor
fuente
0

Icono , 167 163 bytes

procedure f(a,b,c)
!a:=:?a&\x;!c:=:?c&\x;d:=[""]
e:=!b&e[1]==(t:=char(32+ord(a[1,1])))&put(d," "||e)&\x
!d:=:?d&\x;return(!a||"'s"||!d||" "||(k:=!c&t==k[1]&k))
end

Pruébalo en línea!

Utiliza el mismo algoritmo que mi Redrespuesta.

Galen Ivanov
fuente