Implementar funcionalidade semelhante a t9

10

Seu desafio hoje é implementar uma funcionalidade do tipo t9 .

Você implementará uma função que terá apenas 2 parâmetros.
Você receberá 1 número de telefone em uma sequência e o conteúdo de um arquivo de texto com uma lista de palavras (não assuma um estilo específico de nova linha).
Você pode usar o link https://raw.githubusercontent.com/eneko/data-repository/master/data/words.txt para testar a funcionalidade ou usar /usr/share/dict/words(marque Um arquivo de texto com uma lista de palavras [fechada] para mais em formação).

Você pode assumir que sempre receberá pelo menos 2 números.

Dado o número, você lerá uma lista de palavras e retornará as palavras que começam com as letras mapeadas para essas palavras. Isso significa que a entrada deve ser apenas números de 2 a 9.
Você pode fazer o que quiser se receber uma entrada inválida.

Se nenhuma correspondência for encontrada, você poderá retornar uma lista vazia, null/ nilou 0.

Lembre-se de que as teclas do telefone celular são mapeadas para seus caracteres equivalentes:

  • 0 e 1 são inválidos
  • 2 correspondências [abc]
  • 3 combinados [def]
  • 4 correspondências [ghi]
  • 5 correspondências [jkl]
  • 6 correspondências [mno]
  • 7 correspondências [pqrs]
  • 8 correspondências [tuv]
  • e 9 correspondências [wxyz]

Exemplos:

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

Depois de executar sua função, você pode imprimi-la da maneira que desejar.

Regras:

  • As brechas padrão são INVÁLIDAS
  • Você deve retornar algo, mesmo que seja null/ nil
    Javascript retornará undefinedse você não retornar algo, portanto, esta regra.
  • Você não pode usar ou reimplementar as respostas de outras pessoas ou copiar minha implementação.
  • Você pode assumir, para Javascript, que o navegador já estará aberto e que o innerText/ textContentdo elemento automático será passado como o segundo parâmetro
  • Para linguagens compiladas, você não pode passar argumentos especiais para o compilador
  • Você pode receber o nome do arquivo pelos argumentos do compilador
  • Variáveis, macros, variáveis ​​globais, constantes, classes não padrão e toda a classificação que passa outros valores dentro da função serão consideradas inválidas.
  • Em Javascript, variáveis ​​sem a palavra-chave varinvalidam seu código
  • Sua função será nomeada f
  • Você pode ter apenas 2 argumentos em sua função
  • Tente manter seu código em 500 segundos para executar.
  • Você não precisa se preocupar com espaço em branco
  • Você deve usar apenas caracteres imprimíveis ASCII .
    Exceções são idiomas que usam apenas caracteres não imprimíveis (APL e espaço em branco são 2 exemplos).

Pontuação:

  • Menor número de bytes ganhos
  • Ter caracteres imprimíveis ASCII inválidos em sua resposta contará como a resposta sendo codificada em UTF-32.
    A exceção à codificação fará com que sua resposta seja contada por caracteres .
  • Apenas o corpo da função conta, não conte mais nada que você faça fora dele
  • Bônus de -30% se você criar um sistema de previsão com base na vizinhança ou nas palavras mais comuns
  • Bônus de -20% em tamanho, se você retornar apenas as 5 primeiras correspondências para cada letra correspondente ao primeiro número (por exemplo: 245 retornaria 5 palavras começando com 'a', 5 começando com 'b' e 5 começando com 'c' )

Aqui está um exemplo de implementação, 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 executá-lo, abra o link da lista e execute, por exemplo:

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

Este exemplo foi testado e funciona no Opera 12.17 64bits no Windows 7 Home Edition 64bits.

Ismael Miguel
fonte
O segundo argumento para o programa é um nome de arquivo que contém as palavras ou a própria lista de palavras?
Optimizer
@ MartinBüttner O UTF-8 não é injusto (ainda conta caracteres ASCII como sendo de 1 byte), mas mudei a regra.
Ismael Miguel
@Optimizer O segundo argumento é uma lista de palavras. Você pode passar o nome do arquivo sobre um argumento do compilador e ler o arquivo, se desejar. Mas a única coisa que conta é o corpo da função.
Ismael Miguel
@ MartinBüttner Contando como ASCII, está sendo contado como bytes. Você quer que eu diga que o código APL terá 1 byte com o tamanho de 8 bits?
Ismael Miguel
2
-1 para restrições inadequadas
AJMansfield

Respostas:

3

CJam, 28 bytes

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

Recebe entrada na forma de "<number>" [<list of words>]

Exemplo:

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

Resultado:

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

Não vou receber nenhum bônus por enquanto.

Experimente o código online aqui, mas para medições de tempo reais, execute-o no compilador Java

Observe que o CJam representa listas vazias como ""

Para converter a lista de palavras bruta em lista CJam, use o seguinte código com a lista de palavras como entrada:

qN/p
Optimizer
fonte
"Você receberá 1 número de telefone em uma string e o conteúdo de um arquivo de texto com uma lista de palavras" -> você pode implementar, em um bloco diferente, o código necessário para ler o arquivo em uma lista utilizável?
Ismael Miguel
@IsmaelMiguel Você quer dizer não a parte deste código, mas apenas um código auxiliar para converter a lista no formato correto?
Optimizer
Exatamente. O código não é suficiente para provar que ele pode usar uma lista de palavras como os exemplos fornecidos. Mas votei de qualquer maneira, só queria esse código auxiliar.
Ismael Miguel
Você pode adicioná-lo à resposta? Como uma edição, em uma parte diferente
Ismael Miguel
Exatamente. É disso que estou falando! Vamos ver se você pode otimizá-lo ainda mais
Ismael Miguel
2

Java: 395

Isso forma um padrão de regex com base nas letras permitidas para cada número e, em seguida, tachinha um. * No final para corresponder aos caracteres a seguir.

Aqui está a versão do golfe:

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

E aqui está a versão ungolfed para capacidade de leitura

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
fonte
Seu código vai contra a regra número 7: "Variáveis, macros, variáveis ​​globais, constantes, classes não padrão e toda a classificação que passa outros valores dentro da função serão consideradas inválidas." e isso meio que vai contra a regra número 3: "Você não pode usar ou reimplementar as respostas de outras pessoas ou copiar minha implementação.", mas no seu código isso é meio discutível. E isso também contraria a regra 9: "Sua função será nomeada f".
Ismael Miguel
@IsmaelMiguel Oops. A regra 7 pode ser facilmente corrigida movendo a constante dentro da função. Eu estava apenas puxando-o para fora da função para melhorar o estilo de programação. A regra 9 também é uma solução fácil. Confesso que não li sua resposta, por isso não tentei intencionalmente copiá-la. Posso remover minha resposta se você achar que está muito perto do concurso.
Brian J
Sua resposta está bem. Você tem um erro no seu código. Na última constante ( ([W-Zw-z)]) deve ser ([W-Zw-z]). E no Code-golf, você não precisa se preocupar com estilos de programação e boas práticas: seu código deve simplesmente funcionar com os parâmetros necessários. Se você verificar a minha resposta, você verá esta linha: $s=[2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz];. Este é um terrível "crime" em PHP. Basicamente, estou forçando o PHP a converter constantes não existentes em strings. Isso é perfeitamente aceitável. Você também vai ver que eu não estou nem definindo a variável $tpara uma matriz antes de usá-la como tal
Ismael Miguel
@IsmaelMiguel Boa captura do erro regex. Obrigado por apontar isso. Vou tentar jogar golfe amanhã; talvez encontre alguns exemplos de Java neste site.
Brian J
Eu não sou um programador de Java, mas digo algumas coisas. Você pode verificar codegolf.stackexchange.com/questions/6671/… para obter algumas dicas. As dicas gerais incluem a remoção de espaços em branco inúteis (novas linhas, espaços, guias), nomes de variáveis ​​com uma letra e fazem todo o possível para reduzir o tamanho do código o máximo possível.
Ismael Miguel
1

C # .NET 4.5 235

Isso deve 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
fonte
Bem-vindo ao PPCG. Seu código funcionará, mas você ainda precisará reduzi-lo muito mais. Ao remover todo o espaço em branco inútil (espaços, guias, novas linhas), consegui reduzir seu código para 167 bytes. Esse código pode ser reduzido muito mais, tenho certeza. Eu recomendo ler codegolf.stackexchange.com/questions/173/… para reduzir ainda mais o seu código. Para ajudá-lo um pouco, a lista de palavras é uma sequência separada por novas linhas, e você parece assumir que já é possível usar um foreach. Se você espera que já exista IEnumerable, inclua o código usado fora
Ismael Miguel
@IsmaelMiguel TY Vou dar uma olhada. List é um IEnumerable, não há código fora do que eu postei.
Chaossie
Se você olhar para a especificação da função, verá que o 2º parâmetro também é uma string. (Citação: "Você receberá 1 número de telefone em uma string e o conteúdo de um arquivo de texto com uma lista de palavras (não assuma um estilo específico de nova linha).") E você tem 1 espaço em branco inútil no seu avar.
Ismael Miguel
Percebi as melhorias na sua pergunta e dei um voto positivo. Mas você ainda pode salvar um byte no seu avar. Mas realmente vejo melhorias visíveis! Mantenha o bom trabalho.
Ismael Miguel
1

Python 2 (155 bytes)

Também deve funcionar no Python 3 com as substituições apropriadas ( string-> bytes, bprefixo nas strings, etc.).

Eu não tinha certeza se a maketranschamada fora da função é considerada "justa"; caso contrário, a função terá 134 bytes e será movida para dentro.

EDIT: caiu um byte de uma supervisão estúpida.

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

Com maketransno corpo, 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)]

Com importe maketransno corpo, 155 bytes:

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

Chamada de teste:

print f('9999',open('words.txt','rt').read())
criptych fica com Monica
fonte
O maketransfaz parte do corpo da função. Você deveria movê-lo. Não sei se é possível, mas você pode tentar usar diretamente o import. Eu acho que vi em algum lugar ... Mas seu código é muito bom!
Ismael Miguel
Você quer mover a importação e chamar o corpo? Sim, acho que isso também pode ser feito.
Criptych fica com Monica
Eu estava pensando sobre t=(from stirng import maketrans)([...]) . Não faço ideia se é possível. Mas talvez você possa usar o from string import as x t=x([...])que não tenho certeza se é possível também: /
Ismael Miguel
A versão correta é a última. Mas a resposta como está é aceitável na minha opinião. +1 para__import__('string').maketran .
Ismael Miguel
OK obrigado. Eu removi as respostas inválidas.
criptych fica com Monica
0

PHP 5.4+ (171 186-20% = 148,8 bytes):

Bem, esta é uma resposta bastante grande, mas bem.

Espero que isso traga mais pessoas para responder.

Esta função espera que o conteúdo bruto esteja sendo lido.

Aqui está o 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;}

Isso funciona verificando se a letra está na lista de letras permitidas.

Exemplo: a entrada 36faria para verificar se 1abctem a primeira letra da palavra e se 1deftem a segunda letra.

Acrescento 1que não verifique se a carta está na 1ª posição (que retornaria 0e que seria avaliada como false). if(!strpos(1..$s[$c],$v[$i]))ou if(!strpos($c.$s[$c],$v[$i]))terá o mesmo efeito, mas o primeiro confunde mais e eu gosto.

Se não o fizer, removerá a palavra.

Sem palavras, ele retorna uma matriz vazia.

Para testar isso online, acesse http://writecodeonline.com/php/ e crie uma variável simples com uma palavra para linha.

Um exemplo testável:

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

Isso deve gerar:

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

Para trabalhar em versões php mais antigas, substitua $s=[2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz]; por$s=array(2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz);


Para o bônus de 20%:

Para reduzir o código, simplesmente adicionei ||$t[$v[0]]++>4 , que verifica quantas vezes a primeira letra foi usada.

No php, $tnão precisa ser definido, ajudando a reduzir um grande pedaço de 37,2 bytes.

Para ver esse efeito, use a seguinte variável como o segundo argumento:

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