Montar automaticamente uma ária aliterativa de forma previsível

15

Obrigado a @ComradeSparklePony pelo título.

Esse desafio deve ser muito simples. Você recebe três listas.

O primeiro é uma lista dos primeiros nomes, em maiúsculas.

O segundo é uma lista de adjetivos, em minúsculas.

O terceiro é uma lista de substantivos, em minúsculas.

Selecione aleatoriamente um nome, adjetivo opcional e substantivo e saída <Name>'s <adjective> <noun>. No entanto, cada palavra deve começar com a mesma letra. Você pode assumir que todas as palavras começam com uma letra. Você também pode supor (mas anote na sua resposta, se o fizer):

  • que todas as palavras são compostas apenas por caracteres alfabéticos
  • que existe pelo menos um substantivo para cada nome
  • que existe pelo menos um nome para cada substantivo

No entanto, não é possível supor que exista um adjetivo para um par específico de nome e substantivo, pois o adjetivo é opcional, portanto a saída ainda será válida.

Você não precisa selecionar a letra compartilhada de maneira uniforme, embora todas as letras disponíveis devam ter uma chance diferente de zero. Você deve, no entanto, garantir que todas as saídas para uma determinada letra tenham a maior chance possível de ocorrer dentro dos limites do gerador de números aleatórios do seu idioma. No caso do adjetivo, isso equivale a ter uma entrada extra que significa "nenhum adjetivo para esta carta", que tem a mesma chance que todos os outros adjetivos para essa carta.

Exemplos de listas de entrada:

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

Exemplo de saídas para essas entradas (cada linha é um exemplo separado):

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

Observe que não há espaço extra entre as palavras nos dois últimos exemplos.

Isso é , então o código mais curto que não quebra brechas padrão vence!

No caso improvável de ajudar, você pode inserir tudo em maiúsculas, mas ainda precisará produzir em maiúsculas.

Neil
fonte
Estamos corretos ao supor que o programa deve retornar: 1 nome 1 adjetivo (se alguém corresponder ao nome) 1 substantivo? Ou você está pedindo para produzir uma saída para cada nome?
DavidC
1
Talvez você deva adicionar 'Joan' e 'jeep' no seu exemplo para ilustrar o fato de que talvez não haja adjetivo para uma determinada carta?
Arnauld
Dado o seu exemplo de entrada, há a chance de não haver um adjetivo 1 em 3 (já que todas as "listas" do adjetivo são 2 longas)? ... e se 'Joan' e 'Jeep' também estivessem lá sem jadjetivos, a chance seria de 4 em 9? Pode valer a pena colocar probabilidades em relação às saídas ou enumerar todas as saídas - como eu entendo não apenas "todas as saídas para uma determinada letra ...", mas também todas as saídas distintas devem ter a mesma probabilidade (dados distintos em cada lista).
Jonathan Allan
@DavidC Desculpe, eu sei que adicionar exemplos extras tornou isso claro; você produz apenas uma linha de saída para cada chamada.
Neil
1
@JonathanAllan Adicionar "Joan" e "jeep" não afetaria as chances relativas de a saída do "nome de Neil" em comparação com outras opções que contenham "Neil" e "substantivo".
Neil

Respostas:

5

Geléia ,  27 25  24 bytes

-1 graças a Erik the Outgolfer (use um zero em vez de um caractere de espaço)

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

Um programa completo que aceita um argumento na forma de uma lista formatada em Python de listas de strings que imprime a saída em STDOUTt.

Experimente online!

Quão?

Ż€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
fonte
24 bytes .
Erik the Outgolfer
Ah sim, nice :)
Jonathan Allan
5

05AB1E ,  24 23  21 bytes

Assume que existe um substantivo para cada nome, conforme permitido pelo desafio.

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

Experimente online!

Explicação

„'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
fonte
Oh, ¯ªe €˜são inteligentes! Eu tinha uma resposta 26 byte, mas estava tendo dificuldade para fixar o espaço duplo, quando não há um adjetivo ..
Kevin Cruijssen
@KevinCruijssen: Sim, essa foi a parte que eu tive mais problemas também. Demorei um pouco para perceber que eu poderia usar, em ¯vez de encher com cordas vazias, que precisei limpar manualmente mais tarde.
Emigna 13/05/19
4

R , 155 148 bytes

-7 bytes graças 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)}

Experimente online!

Utiliza amostragem por rejeição: desenhe aleatoriamente um nome, um adjetivo (possivelmente a string vazia) e um substantivo até que as primeiras letras correspondam. Essa condição é verificada contando se o número de elementos únicos no vetor formado das primeiras letras, mais a sequência vazia, é de comprimento 2 - isso permite um adjetivo vazio.

Em seguida, imprima o resultado, com um espaço extra se o adjetivo não estiver vazio.

As diferentes possibilidades que começam com a mesma letra têm probabilidades de ocorrência iguais, uma vez que se samplebaseiam na distribuição uniforme. A maneira mais fácil de ver isso é condicionar, no evento, que o nome e o nome comecem com a mesma letra (o que é bom: se não o fizerem, rejeitaremos). Agora, condicione o evento que aceitamos: isso significa que desenhamos o adjetivo vazio ou um adjetivo começando com a mesma letra. Cada uma dessas possibilidades ainda tem igual probabilidade.

105

Robin Ryder
fonte
Isso tem a mesma chance de um adjetivo vazio entre si, para uma primeira letra?
Nick Kennedy
@NickKennedy Sim, já que se samplebaseia na distribuição uniforme. A maneira mais fácil de ver isso é condicionar, no evento, que o nome e o nome comecem com a mesma letra (o que é bom: se não o fizerem, rejeitaremos). Agora, condicione o evento que aceitamos: isso significa que desenhamos o adjetivo vazio ou um adjetivo começando com a mesma letra. Cada uma dessas possibilidades ainda tem igual probabilidade.
Robin Ryder
obrigado, bem explicado.
Nick Kennedy
@NickKennedy Obrigado, vou adicionar essa explicação ao post junto com um link para verificar empiricamente que as probabilidades são iguais.
Robin Ryder
1
148 bytes
Giuseppe
3

JavaScript (ES6),  139 124 122  120 bytes

Economize 2 bytes graças 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)

Experimente online!

Ou verifique a distribuição em 5 milhões de empates

Quão?

A função auxiliar g pega uma matriz e retorna um elemento aleatório dessa matriz, com uma distribuição uniforme.

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

Invocando g três vezes, geramos uma sequência aleatória scom um formato válido, mas sem levar em consideração as letras iniciais. Para o adjetivo, anexamos uma entrada vazia e certifique-se de não inserir um espaço à direita, se for escolhido.

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

Em seguida, verificamos se todas as letras iniciais são idênticas à seguinte expressão regular:

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

Não, simplesmente tentamos novamente até s é válido.

Arnauld
fonte
+[(o=g([,...a]))&&o+' ']+economiza 2 bytes, eu acho?
Neil
@ Neil Ah, sim. Agradável.
Arnauld
3

Python 3 , 161 154 151 151 147 145 bytes

( Obrigado ArBo, EmbodimentOfIgnorance, Neil, que contribuiu com 2, 3 e 4 bytes para o meu primeiro golfe! )

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)

Experimente online! (com 500k execuções)

  • Toma três listas como entradas.

  • Assume pelo menos um substantivo para cada nome.


Mesma pontuação, mais golfe:

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])

Experimente online! (com 500k execuções)

É apenas 140 se os espaços em branco à direita forem permitidos (removendo a face quadrada [:-1])

Nicola Sap
fonte
1
Boa primeira resposta! Você pode salvar um byte no primeiro loop while: while t>""<t[0]!=w. Você também pode substituir a última linha print(s+"'s",t+(t and" ")+o), soltando a u=na terceira linha.
ArBo 12/05/19
Acabei mudando minha solução, porque o anterior não se adequar às exigências
Nicola Sap
1
152 bytes (rodapé removido para caber no URL no comentário)
Modalidade de ignorância
1
Você está usando a variável apenas tuma vez para poder salvar 4 bytes incorporando o código. Eu acho que você pode mudar opara usar um padrão de código semelhante te salvar outros 4 bytes, incorporando isso também.
Neil
Obrigado, vocês estão realmente ajudando! @Neil, eu não ser capaz de refatorar o: eu chegar a este: 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 ), mas acrescentando o espaço em branco condicional, através de uma arg opcional y, custa-me 11 bytes
Nicola Sap
0

Gelatina , 28 bytes

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

Experimente online!

Escrevi isso antes de ver a resposta mais curta de @ JonathanAllan, mas achei que valeria a pena postar, pois usa uma abordagem diferente. Salvo 3 bytes pela sugestão de @ EriktheOutgolfer nessa resposta.

Um programa completo que obtém uma lista de listas de seqüências de caracteres e imprime implicitamente uma aliteração selecionada aleatoriamente. Assume pelo menos um substantivo por nome.

Nick Kennedy
fonte
0

C # (compilador interativo do 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();

Experimente online!

Modalidade de ignorância
fonte
Você pode assumir que os nomes começam com uma letra maiúscula; portanto, você pode apenas maiúsculas as outras letras da comparação, o que deve economizar 10 bytes?
Neil
@ Neil Sim, exatamente 10 bytes :)
Modalidade de Ignorância
0

Vermelho , 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]]

Experimente online!

Explicação:

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
fonte
0

Scala , 234 226 234 206 bytes

-28 devido ao fato de eu ter que aceitar o StdIn, agora é uma função

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

Experimente online!

Ungolfed:

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

Experimente online!

Value Ink
fonte
0

Ícone , 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

Experimente online!

Usa o mesmo algoritmo da minha Redresposta.

Galen Ivanov
fonte