Ode Golf - Exclusões de letras

17

Dado um arquivo de dicionário (um arquivo de texto contendo uma palavra ou frase em cada linha, com pontuação possível, mas sem números; as linhas são alfabetizadas), você deve exibir cada combinação de palavras em que uma letra pode ser removida de uma palavra para formar outra; a letra removida deve estar entre parênteses.

Por exemplo, a entrada

cat
cart
code
golf
ode
verify
versify

deve dar uma saída de

ca(r)t
(c)ode
ver(s)ify

Várias maneiras de obter o mesmo par devem ser exibidas apenas uma vez. Você pode produzir scra(p)pedou scrap(p)ed, mas não ambos.

A saída deve ser ordenada alfabeticamente pela entrada mais longa;

mart
mar
mat
ma

deve ter uma saída de

ma(r)
ma(t)
ma(r)t
mar(t)

e os dois últimos podem estar em qualquer ordem.

O arquivo do dicionário pode incluir letras maiúsculas, espaços, hífens ou apóstrofos; estes devem ser ignorados. Por exemplo,

inlay 
in-play

deve produzir in(p)lay. Sua saída deve estar no mesmo caso. Espaço em branco extra é permitido.

A entrada pode ser STDIN ou de um arquivo; é separado por novas linhas. A saída pode ser o valor de retorno de uma função ou STDOUT (ou gravada em um arquivo, se você desejar).

Isso é , então o código mais curto em bytes vence.

(Este é o meu primeiro desafio no PPCG - deixe-me saber se fiz algo errado e vou consertar.)

Deusovi
fonte
3
Qual deve ser a saída mart mar mat ma? Seria mar(t) ma(r)t ma(r) ma(t)?
Sp3000 28/09/2015
@ Sp: Esqueci de especificar o pedido - editado para esclarecer.
Deusovi 28/09/15
No primeiro exemplo, a palavra golfe não está na saída. Isso é porque é uma palavra que não tem outras combinações?
LukStorms
@Luk: Sim! Para a maioria dos arquivos de dicionário, haverá muitas palavras que não produzem outras palavras - elas não devem aparecer em nenhum lugar da saída.
Deusovi
2
Que tal permitir uma função com um parâmetro de string (grande), retornando a saída solicitada como uma matriz de strings? Isso colocou o foco no algoritmo, evitando a necessidade de gerenciar a E / S de arquivo.
Edc65 28/09/2015

Respostas:

1

Perl -an0, 101 + 3 bytes

@F=sort{length$a<=>length$b}map{s/\W//g;lc}@F;map{$`.$'~~@F?print"$`($1)$'\n":$\while/(.)(?!\1)/g}@F;

Onde

  • @Fé o dicionário, armazenado em uma matriz, fornecido pelo sinalizador de tempo de execução mágico. (b-oost, BoO # @% @ # $% $ # @ T)
  • map{s/\W//g;lc}@Fremove todos os símbolos das palavras e transforma tudo em minúsculas. (impulso, inicialização)
  • sort{length$b<=>length$a}classifica em comprimento. (inicialização, aumento)
  • map{ (...) while/(.)(?!\1)/g}@Fcorresponde a todos os caracteres que não são seguidos pelo mesmo caractere ([b] oot, bo [o] t, boo [t], ...)
  • print"$`($1)$'\n"imprime as peças que precedem, entre parênteses e conseguem uma correspondência ... (vaia (s) t)
  • if $`.$'~~@F... se a concatenação de tudo antes e depois da partida estiver no dicionário. ([impulso])
bopjesvla
fonte
5

JavaScript (ES6), 225

Uma função com um parâmetro de sequência, sem entrada do arquivo. Perguntei à OP se isso poderia ser válido.

Teste a execução do snippet em um navegador compatível com EcmaScript 6 (implementando funções de seta, sequência de modelos, operador de propagação - Firefox, talvez Safari ou MS Edge, não Chrome)

f=t=>t.split`
`.map(w=>(d[k=w.replace(/\W/g,'').toLowerCase()]={},k),d={},r=[]).map(w=>[...w].map((c,i,v)=>(d[v[i]='',x=v.join``]&&!d[x][w]&&r.push(d[x][w]=(v[i]=`(${c})`,v.join``)),v[i]=c)))&&r.sort((a,b)=>a.length-b.length)

// LESS GOLFED

Q=t=>{
  // convert to canonical form and put in a dictionary
  // each value in the dictionary is an hashtable tha will store the list
  // of words that can generate the current word, removing a letter
  d={},
  t=t.split`\n`.map(w=>(k=w.replace(/\W/g,'').toLowerCase(),d[k]={},k))
  r=[], // result array 
  t.forEach(w =>
    [...w].forEach((c,i,v)=>( // for each letter in word, try to remove
      v[i]='', x=v.join``, // build string with missing letter
      v[i]='('+c+')', y=v.join``, // and build string with brackets
      v[i]=c, // restore the current letter
      d[x] && // if the word with removed letter is present in the dictionary
      !d[x][w] && // and not already from the same generating word
         r.push(d[x][w]=y) // update dictionary and add word to result array
    ))
  )
  return r.sort((a,b)=>a.length-b.length) // sort result by length
}  

// TEST
function test() { R.innerHTML=f(I.value) }
textarea { height: 20em }
Test <button onclick="test()">-></button>
<span id=R></span>
<br><textarea id=I>cat
cart
code
golf
node
scraped
scrapped
verify
versify
mart
mar
mat
ma</textarea>

edc65
fonte
@ETHproductions right, thx
edc65
3

Ruby, 173

->d{o=[]
c={}
d=d.sort_by{|w|[w.size,w]}.map{|w|w=w.upcase.gsub /[^A-Z]/,''
c[w]=l=1
w.size.times{|i|p,x,s=w[0...i],w[i],w[i+1..-1]
c[p+s]&&l!=x&&o<<p+"(#{w[i]})"+s
l=x}}
o}

Teste aqui: http://ideone.com/86avbe

Versão legível aqui: http://ideone.com/ynFItB

Cristian Lupascu
fonte
No celular, não posso testar agora - você poderia adicionar um caso de teste para o SCRAPPED / SCRAPED?
Deusovi
@ Deusovi Esse caso não funciona corretamente. Eu estou fixando-o agora ...
Cristian Lupascu
@Deusovi Updated!
Cristian Lupascu 28/09/2015
Esta resposta não fornece a saída correta para, por exemplo, o ['jacklantern','jackslantern','jack-o-lantern']ditado.
precisa saber é o seguinte
11
@ 14mRh4X0r não consegue encontrar esse pedido na questão ... The output should be ordered by the longer entry;...and the latter two could be in either order.
edc65
1

Ruby, 211

Decidi adotar uma abordagem diferente para resolver isso, usando o regex.

->d{o=[]
d.map{|x|x.upcase!.gsub! /[-' ]/,''}
d.map{|x|(x.size+1).times{|i|o+=d.map{|w|w.b.sub! /(#{x[0...i]})(.)(#{x[i..-1]})/,'\1(\2)\3'if w[i]!=w[i+1]}}}
o.compact.sort_by{|w|[w.size,w.gsub(/[()]/,'')]}.uniq}
14mRh4X0r
fonte
0

Perl 5, 210

O código carrega a entrada em uma matriz classificada e verifica cada valor em relação a todos os valores da matriz com 1 byte a mais.

map{@W=split//,$w=$_;map{@X=split//,$x=$_;if(@W+1==@X){$i=0;while($W[$i]eq$X[$i]&&$i<@W){$i++}$c=$X[$i];$e=substr($w,$i);print substr($w,0,$i)."($c)$e\n",if substr($x,$i+1)eq$e}}@D}@D=sort(map{s/[^\w]//g;lc}<>)

Teste

$ perl dictionairy_same_words.pl dictionairywords.txt
ca(r)t
in(p)lay
ma(r)
ma(t)
mar(t)
ma(r)t
(c)ode
ver(s)ify
LukStorms
fonte
0

Haskell, 201 bytes

import Data.List
import Data.Char
a#(b:c)=(a,b,c)
g a=[l++'(':m:')':n|x<-a,((l,m,n):_)<-[[o|o@(i,j,k)<-zipWith(#)(inits x)$init$tails x,elem(i++k)a]]]
f=sortOn length.g.map(filter isLetter.map toLower)

Não tenho certeza de qual formato de entrada é permitido. fpega uma lista de strings. Se apenas uma única string (com nl palavras separadas) for permitida, adicione .linesa f(+6 bytes).

Exemplo de uso:

f ["cat","cart","code","golf","od-e","verify","versify","on","s-o-n","Scrapped","scraped"]

["(s)on","ca(r)t","(c)ode","ver(s)ify","scra(p)ped"]

Como funciona: coloque todas as palavras em minúsculas e mantenha apenas as letras. Divida cada palavra xem duas partes em todas as posições possíveis e faça triplos (i,j,k)onde iestá a primeira parte, jé o primeiro caractere da segunda parte e ké a cauda da segunda parte. Mantenha os triplos onde i++ktambém aparece na lista de palavras. Se esta lista não estiver vazia, pegue o primeiro elemento, chame-o (l,m,n). Transforme todas essas cabeças de lista no formato de saída desejado, envolvendo m-o ()e colocando-o entre le n.

nimi
fonte