Implemente la funcionalidad de tipo t9

10

Su desafío hoy es implementar una funcionalidad similar a t9 .

Implementará una función que solo tendrá 2 parámetros.
Recibirá 1 número de teléfono en una cadena y el contenido de un archivo de texto con una lista de palabras (no asuma un estilo específico de nueva línea).
Puede usar el enlace https://raw.githubusercontent.com/eneko/data-repository/master/data/words.txt para probar la funcionalidad, o usar /usr/share/dict/words(consulte un archivo de texto con una lista de palabras [cerrado] para obtener más información) información).

Puede suponer que siempre recibirá al menos 2 números.

Dado el número, leerá de una lista de palabras y devolverá las palabras que comienzan con el mapeo de letras a esas palabras. Esto significa que la entrada debe ser solo números del 2 al 9.
Puede hacer lo que quiera si recibe una entrada no válida.

Si no se encuentra ninguna coincidencia, puede devolver una lista vacía, null/ nilo 0.

Recuerde que las teclas del teléfono celular se asignan a sus caracteres equivalentes:

  • 0 y 1 no son válidos
  • 2 partidos [abc]
  • 3 coincidentes [def]
  • 4 partidos [ghi]
  • 5 coincidencias [jkl]
  • 6 partidos [mno]
  • 7 coincidencias [pqrs]
  • 8 partidos [tuv]
  • y 9 coincidencias [wxyz]

Ejemplos:

f('52726')
//returns ["Japan","japan","Japanee","Japanese","Japanesque"...,"larbowlines"]

f('552')
//returns ["Kjeldahl","kjeldahlization","kjeldahlize"...,"Lleu","Llew"]

f('1234')
//makes demons fly out your nose or divide by 0

f('9999')
//returns ["Zyzzogeton"]

f('999999')
//returns [] or null/nil or 0

Después de ejecutar su función, puede imprimirla de la forma que desee.

Reglas:

  • Las lagunas estándar son inválidas
  • Debe devolver algo, incluso si es null/ nil
    Javascript devolverá undefinedsi no devuelve algo, por lo tanto, esta regla.
  • No puede usar o volver a implementar las respuestas de otros ni copiar mi implementación.
  • Puede suponer, para Javascript, que el navegador ya estará abierto y que el innerText/ textContentdel elemento automático se pasará como el segundo parámetro
  • Para lenguajes compilados, no puede pasar argumentos especiales al compilador
  • Puede recibir el nombre del archivo sobre los argumentos del compilador
  • Las variables, macros, variables globales, constantes, clases no estándar y todo el tipo que pasa otros valores dentro de la función se considerarán inválidas.
  • En Javascript, las variables sin la palabra varclave invalidan su código
  • Su función será nombrada f
  • Solo puedes tener 2 argumentos en tu función
  • Intenta mantener tu código por debajo de 500 segundos para ejecutarlo.
  • No tiene que preocuparse por los espacios en blanco.
  • Debe usar solo caracteres imprimibles ASCII .
    Las excepciones son idiomas que solo usan caracteres no imprimibles (APL y espacios en blanco son 2 ejemplos).

Puntuación:

  • El menor número de bytes gana
  • Tener caracteres imprimibles ASCII no válidos en su respuesta contará como la respuesta codificada en UTF-32.
    La excepción a la codificación hará que su respuesta se cuente por caracteres .
  • Solo cuenta el cuerpo de la función, no cuentes nada más que hagas fuera de él
  • Bonificación de -30% si realiza un sistema de predicción basado en el vecindario o las palabras más comunes
  • Bono de -20% si solo devuelve las primeras 5 coincidencias para cada letra correspondiente al primer número (por ejemplo: 245 devolvería 5 palabras que comienzan con 'a', 5 que comienzan con 'b' y 5 que comienzan con 'c' )

Aquí hay un ejemplo de una implementación, usando Javascript:

function f(phone, words)
{
    var keypad=['','','abc','def','ghi','jkl','mno','pqrs','tuv','wxyz'];
    var regex='';

    for(var i=0,l=phone.length;i<l;i++)
    {
        regex+='['+keypad[phone[i]]+']';
    }

    var regexp=new RegExp('\\s('+regex+'[a-z]*)\\s','gi');

    return words.match(regexp);
}

Para ejecutarlo, abra el enlace de la lista y ejecute, por ejemplo:

f('9999',document.getElementsByTagName('pre')[0].innerText);
//returns [" Zyzzogeton "]

Este ejemplo fue probado y funciona bajo Opera 12.17 64bits en Windows 7 Home Edition 64bits.

Ismael Miguel
fuente
¿Es el segundo argumento para el programa un nombre de archivo que contiene las palabras o la lista de palabras en sí?
Optimizador
@ MartinBüttner UTF-8 no es injusto (todavía cuenta los caracteres ASCII como 1 byte), pero cambié la regla.
Ismael Miguel
@Optimizer El segundo argumento es una lista de las palabras. Puede pasar el nombre del archivo sobre un argumento del compilador y leer el archivo, si lo desea. Pero lo único que cuenta es el cuerpo de la función.
Ismael Miguel
@ MartinBüttner Al contar como ASCII, se cuenta como bytes. ¿Quiere que le diga que el código APL tendrá 1 byte con un tamaño de 8 bits?
Ismael Miguel
2
-1 por restricciones inapropiadas
AJMansfield

Respuestas:

3

CJam, 28 bytes

q~{el{'h-_9/-D+3/}%s1$#!},p;

Toma entrada en forma de "<number>" [<list of words>]

Ejemplo:

"52726" ["Japan" "japan" "Japanee" "Japanese" "Japanesque" "larbowlines" "ablution" "ablutionary" "abluvion" "ably" "abmho" "Abnaki" "abnegate"]

Salida:

["Japan" "japan" "Japanee" "Japanese" "Japanesque" "larbowlines"]

No voy por ninguna bonificación por ahora.

Pruebe el código en línea aquí, pero para mediciones de tiempo real, ejecútelo en el compilador de Java

Tenga en cuenta que CJam representa listas vacías como ""

Para convertir la lista de palabras sin formato en la lista de CJam, use el siguiente código con la lista de palabras como entrada:

qN/p
Optimizador
fuente
"Recibirá 1 número de teléfono en una cadena y el contenido de un archivo de texto con una lista de palabras" -> ¿puede implementar, en un bloque diferente, el código necesario para leer el archivo en una lista utilizable?
Ismael Miguel
@IsmaelMiguel ¿Quiere decir que no es la parte de este código, sino solo un código auxiliar para convertir la lista al formato correcto?
Optimizador
Exactamente. Su código no es suficiente para demostrar que puede usar una lista de palabras como ejemplos proporcionados. Pero voté de todos modos, solo quería ese código auxiliar.
Ismael Miguel
¿Puedes agregarlo a la respuesta? Como una edición, en una parte diferente
Ismael Miguel
Exactamente. ¡De eso estoy hablando! Veamos si puedes optimizarlo aún más
Ismael Miguel
2

Java: 395

Esto forma un patrón regex basado en las letras permitidas para cada número, y luego agrega un. * Al final para que coincida con los siguientes caracteres.

Aquí está la versión de golf:

static ArrayList<String> f(String n,ArrayList<String> d){String[] k={"","","([A-Ca-c])","([D-Fd-f])","([G-Ig-i])","([J-Lj-l])","([M-Om-o])","([P-Sp-s])","([T-Vt-v])","([W-Zw-z])"};String r="";for(int i=0;i<n.length();++i)r+=k[n.charAt(i)-'0'];r += ".*";Pattern p=Pattern.compile(r);ArrayList<String> a=new ArrayList<String>();for(String w:dictionary)if(p.matcher(w).matches())a.add(w);return a;}

Y aquí está la versión no adaptada para la capacidad de lectura

public static ArrayList<String> f(String phoneNumber, ArrayList<String> dictionary) {

    String[] KEY_VALUES = {"", "", "([A-Ca-c])", "([D-Fd-f])", "([G-Ig-i])",
                                            "([J-Lj-l])", "([M-Om-o])", "([P-Sp-s])",
                                            "([T-Vt-v])", "([W-Zw-z])"};

    String regex = "";
    for (int i = 0; i < phoneNumber.length(); ++i) {
        regex += KEY_VALUES[phoneNumber.charAt(i) - '0'];
    }
    regex += ".*";
    Pattern p = Pattern.compile(regex);
    ArrayList<String> answers = new ArrayList<String>();
    for (String word : dictionary) {
        if (p.matcher(word).matches()) {
            answers.add(word);
        }
    }
    return answers;
}
Brian J
fuente
Su código va en contra de la regla número 7: "Las variables, macros, variables globales, constantes, clases no estándar y todo el tipo que pasa otros valores dentro de la función se considerarán inválidos". y va en contra de la regla número 3: "No puedes usar o volver a implementar las respuestas de otros o copiar mi implementación", pero en tu código es algo discutible. Y también va en contra de la regla 9: "Su función será nombrada f".
Ismael Miguel
@IsmaelMiguel Oops. La regla 7 se puede arreglar fácilmente moviendo la constante dentro de la función. Solo lo estaba sacando de la función para un mejor estilo de programación. La regla 9 también es una solución fácil. Confieso que no leí tu respuesta, así que no intenté copiarla intencionalmente. Puedo eliminar mi respuesta si crees que está demasiado cerca para el concurso.
Brian J
Tu respuesta está bien. Tienes un error en tu código. En la última constante ( ([W-Zw-z)]) debería estar ([W-Zw-z]). Y en Code-golf no tiene que preocuparse por los estilos de programación y las buenas prácticas: su código simplemente debe hacer sus cosas dentro de los parámetros requeridos. Si revisas mi respuesta, verá esta línea: $s=[2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz];. Este es un horrible 'crimen' en PHP. Básicamente estoy obligando a PHP a convertir constantes no existentes en cadenas. Esto es perfectamente aceptable. También verá que ni siquiera estoy configurando la variable $ten una matriz antes de usarla como tal
Ismael Miguel,
@IsmaelMiguel Buena captura del error regex. Gracias por mencionarlo. Intentaré jugar golf mañana; tal vez encuentre algunos ejemplos de Java en este sitio.
Brian J
No soy un programador de Java, pero te digo algunas cosas. Puede consultar codegolf.stackexchange.com/questions/6671/… para obtener algunos consejos. Los consejos generales incluyen la eliminación de espacios en blanco inútiles (líneas nuevas, espacios, pestañas), nombres de variables de una letra y hacer todo lo posible para reducir el tamaño del código tanto como sea posible.
Ismael Miguel
1

C # .NET 4.5 235

Esto debería funcionar:

IEnumerable<string>F(string n,string d){IEnumerable<string>w=d.Split(null).ToList();string[]a={"","","abc","def","ghi", "jkl","mno","pqrs","tuv","wxyz"};foreach(var i in n){w=w.Where(x=>x.IndexOfAny(a[i-'0'].ToArray())>0);}return w;}
Chaossie
fuente
Bienvenido a PPCG. Su código funcionará, pero aún necesita reducirlo mucho más. Al eliminar todos los espacios en blanco inútiles (espacios, tabulaciones, líneas nuevas), he logrado reducir su código a 167 bytes. Este código se puede reducir mucho más, estoy seguro. Recomiendo leer codegolf.stackexchange.com/questions/173/… para acortar aún más su código. Para ayudarlo un poco, la lista de palabras es una cadena separada por nuevas líneas, y parece asumir que ya es posible usar un foreach. Si espera que ya sea así IEnumerable, incluya el código que se usa afuera
Ismael Miguel
@IsmaelMiguel TY Lo miraré. La lista es un IEnumerable, no hay código fuera de lo que publiqué.
Chaossie
Si observa la especificación de la función, verá que el segundo parámetro también es una cadena. (Cita: "Recibirá 1 número de teléfono en una cadena y el contenido de un archivo de texto con una lista de palabras (no asuma un estilo específico de nueva línea)"). Y tiene 1 espacio en blanco inútil en su avar.
Ismael Miguel
He notado las mejoras en su pregunta, y le di un voto a favor. Pero aún puede guardar un byte en su avar. ¡Pero realmente veo mejoras notables! Sigan con el buen trabajo.
Ismael Miguel
1

Python 2 (155 bytes)

También debería funcionar en Python 3 con los reemplazos apropiados ( string-> bytes, bprefijo en cadenas, etc.).

No estaba seguro de si tener la maketransllamada fuera de la función se considera "justo"; si no, la función es de 134 bytes con ella movida dentro.

EDITAR: Se cayó un byte de una estúpida supervisión.

Con preparado maketrans, 67 bytes:

from string import maketrans
t=maketrans('abcdefghijklmnopqrstuvwxyz','22233344455566677778889999')

def f(n,w):
    return[x for x in w.split()if x.lower().translate(t).startswith(n)]

Con maketransen el cuerpo, 134 bytes:

from string import maketrans

def f(n,w):
    return[x for x in w.split()if x.lower().translate(maketrans('abcdefghijklmnopqrstuvwxyz','22233344455566677778889999')).startswith(n)]

Con importy maketransen cuerpo, 155 bytes:

def f(n,w):
    return[x for x in w.split()if x.lower().translate(__import__('string').maketrans('abcdefghijklmnopqrstuvwxyz','22233344455566677778889999')).startswith(n)]

Llamada de prueba:

print f('9999',open('words.txt','rt').read())
criptych está con Monica
fuente
El maketranses parte del cuerpo de la función. Deberías moverlo. No sé si es posible, pero puedes intentar usar directamente el import. Creo que lo vi en alguna parte ... ¡Pero tu código es realmente bueno!
Ismael Miguel
¿Quieres decir mover la importación y llamar al cuerpo? Sí, creo que eso también se puede hacer.
Criptych está con Mónica el
Estaba pensando en eso t=(from stirng import maketrans)([...]). No tengo idea si es posible. Pero tal vez pueda usar lo from string import as x t=x([...])que no estoy seguro si también es posible: /
Ismael Miguel
La versión correcta es la última. Pero la respuesta tal cual es aceptable en mi opinión. +1 para __import__('string').maketran.
Ismael Miguel
OK gracias. He eliminado las respuestas inválidas.
Criptych está con Monica el
0

PHP 5.4+ (171 186-20% = 148.8 bytes):

Bueno, esta es una gran respuesta, pero bueno.

Espero que esto atraiga a más personas para responder.

Esta función espera que el crudo contenido que está siendo leído.

Aquí está el código:

function f($_,$a){$s=[2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz];$a=preg_split('@\r\n|\r|\n@',$a);for($i=0;$c=$_[$i];++$i)foreach($a as$k=>$v)if(!strpos(1..$s[$c],$v[$i])||$t[$v[0]]++>4)unset($a[$k]);return$a;}

Esto funciona verificando que la letra está en la lista de letras permitidas.

Ejemplo: la entrada 36haría para verificar si 1abctiene la primera letra de la palabra y si 1deftiene la segunda letra.

Anexo 1para que no verifique si la carta está en la primera posición (que volvería 0y que evaluaría false). if(!strpos(1..$s[$c],$v[$i]))o if(!strpos($c.$s[$c],$v[$i]))tendrá el mismo efecto, pero el primero confunde más y me gusta.

De lo contrario, eliminará la palabra.

Sin palabras restantes, devuelve una matriz vacía.

Para probar esto en línea, vaya a http://writecodeonline.com/php/ y cree una variable simple con una palabra para línea.

Un ejemplo comprobable:

function f($_,$a)
{
    $s=array(2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz);
    $a=preg_split('@\r\n|\r|\n@',$a);

    for($i=0;$c=$_[$i];++$i)
        foreach($a as$k=>$v)
            if(!strpos(1..$s[$c],$v[$i]) || $t[$v[0]]++>4)
                unset($a[$k]);
    return$a;
}

$lines=<<<WORDS
one
two
three
four
five
six
seven
eight
nine
ten
WORDS;

var_dump(f('36',$lines));

Esto debería generar:

array(1) {
    [3]=>
      string(4) "four"
}

Para trabajar en versiones anteriores de php, reemplace $s=[2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz];por$s=array(2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz);


Para el bono del 20%:

Para reducir el código, simplemente agregué ||$t[$v[0]]++>4, que comprueba cuántas veces se usó la primera letra.

En php, $tno es necesario definirlo, lo que ayuda a reducir una gran parte de 37,2 bytes.

Para ver este efecto, use la siguiente variable como segundo argumento:

$lines=<<<WORDS
one
two
three
four
five
six
seven
eight
nine
ten
twelve
time
tutor
test
truth
WORDS;
Ismael Miguel
fuente