Ode Golf - Supresiones de cartas

17

Dado un archivo de diccionario (un archivo de texto que contiene una palabra o frase en cada línea, con posible puntuación pero sin números; las líneas están ordenadas alfabéticamente), debe generar cada combinación de palabras donde una letra puede eliminarse de una palabra para formar otra; la letra eliminada debe estar entre paréntesis.

Por ejemplo, la entrada

cat
cart
code
golf
ode
verify
versify

debería dar una salida de

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

Múltiples formas de obtener el mismo par solo deben mostrarse una vez. Puede generar scra(p)pedo scrap(p)ed, pero no ambos.

La salida debe ordenarse alfabéticamente por la entrada más larga;

mart
mar
mat
ma

debe tener una salida de

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

y los dos últimos podrían estar en cualquier orden.

El archivo del diccionario puede incluir mayúsculas, espacios, guiones o apóstrofes; Estos deben ser ignorados. Por ejemplo,

inlay 
in-play

debe producir in(p)lay. Su salida debería estar en el mismo caso. Se permite espacio en blanco adicional.

La entrada puede ser STDIN o de un archivo; Está separado por nuevas líneas. La salida puede ser el valor de retorno de una función o STDOUT (o escrito en un archivo si lo desea).

Este es el , por lo que gana el código más corto en bytes.

(Este es mi primer desafío en PPCG; avíseme si he hecho algo mal y lo solucionaré).

Deusovi
fuente
3
¿Para qué debería ser la salida mart mar mat ma? ¿Lo sería mar(t) ma(r)t ma(r) ma(t)?
Sp3000
@Sp: Olvidé especificar el orden, editado para aclarar.
Deusovi
En el primer ejemplo, la palabra golf no está en la salida. ¿Es porque es una palabra que no tiene otras combinaciones?
LukStorms
@Luk: ¡Sí! Para la mayoría de los archivos de diccionario, habrá muchas palabras que no forman otras palabras, que no deberían aparecer en ninguna parte de la salida.
Deusovi
2
¿Qué pasa con permitir una función con un parámetro de cadena (grande), devolviendo la salida solicitada como una matriz de cadena? Esto puso el foco en el algoritmo, evitando la necesidad de administrar las E / S de archivos.
edc65

Respuestas:

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;

dónde

  • @Fes el diccionario, almacenado en una matriz, proporcionado por runtime flag magic. (b-oost, BoO # @% @ # $% $ # @ T)
  • map{s/\W//g;lc}@Felimina todos los símbolos de las palabras y convierte todo en minúsculas. (impulso, arranque)
  • sort{length$b<=>length$a}Se clasifica en longitud. (arranque, impulso)
  • map{ (...) while/(.)(?!\1)/g}@Fcoincide con todos los caracteres que no son seguidos por el mismo carácter ([b] oot, bo [o] t, boo [t], ...)
  • print"$`($1)$'\n"imprime las partes que preceden, paréntesis y suceden una coincidencia ... (boo (s) t)
  • if $`.$'~~@F... si la concatenación de todo antes y después del partido está en el diccionario. ([aumentar])
bopjesvla
fuente
5

JavaScript (ES6), 225

Una función con un parámetro de cadena, sin entrada del archivo. Le pregunté a OP si esto podría ser válido.

Pruebe ejecutar el fragmento en un navegador compatible con EcmaScript 6 (implementando funciones de flecha, cadena de plantilla, operador de propagación: Firefox, tal vez Safari o MS Edge, no 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
fuente
@ETHproductions bien, gracias
edc65
3

Rubí, 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}

Pruébelo aquí: http://ideone.com/86avbe

Versión legible aquí: http://ideone.com/ynFItB

Cristian Lupascu
fuente
En el móvil, así que no puedo probar en este momento, ¿podría agregar un caso de prueba para SCRAPPED / SCRAPED?
Deusovi
@Deusovi Ese caso no funciona correctamente. Lo estoy arreglando ahora ...
Cristian Lupascu
@Deusovi ¡Actualizada!
Cristian Lupascu
Esta respuesta no proporciona la salida correcta para, por ejemplo, el ['jacklantern','jackslantern','jack-o-lantern']dict.
14mRh4X0r
1
@ 14mRh4X0r no puede encontrar esa solicitud en la pregunta ... The output should be ordered by the longer entry;...and the latter two could be in either order.
edc65
1

Rubí, 211

Decidí tomar un enfoque diferente para resolver esto, usando expresiones regulares.

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

Perl 5, 210

El código carga la entrada en una matriz ordenada y comprueba cada valor con todos los valores de la matriz que son 1 byte más largos.

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

Prueba

$ 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
fuente
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)

No estoy seguro de qué formato de entrada está permitido. ftoma una lista de cadenas. Si solo se permite una sola cadena (con nl palabras separadas), agregue .linesa f(+6 bytes).

Ejemplo 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"]

Cómo funciona: cambie cada palabra a minúsculas y conserve solo las letras. Divida cada palabra xen dos partes en cada posición posible y haga triples (i,j,k)donde iestá la primera parte, jes el primer carácter de la segunda parte y kes la cola de la segunda parte. Mantenga los triples donde i++ktambién aparece en la lista de palabras. Si esta lista no está vacía, tome el primer elemento, llámelo (l,m,n). Convierta todos esos encabezados de lista en el formato de salida requerido rodeando mcon ()y colocándolo entre ly n.

nimi
fuente