实现类似t9的功能


10

今天的挑战是实现类似t9的功能。

您将实现一个只有2个参数的函数。
您将收到一个字符串形式的电话号码,以及一个带有单词列表的文本文件的内容(不要使用特定的换行符样式)。
您可以使用链接https://raw.githubusercontent.com/eneko/data-repository/master/data/words.txt来测试功能,或使用/usr/share/dict/words(检查的文本文件的单词列表[关闭]更多信息)。

您可以假设您将始终收到至少两个数字。

给定数字,您将从单词列表中读取并返回以映射到这些单词的字母开头的单词。这意味着输入只能是2到9之间的数字。
如果收到无效的输入,则可以执行任何操作。

如果没有找到匹配的,你可以返回一个空列表,null/ nil0

请记住,手机密钥已映射到它们的等效字符:

  • 0和1无效
  • 2个匹配项[abc]
  • 3个符合的[def]
  • 4场比赛[吉]
  • 5个匹配项[jkl]
  • 6场比赛[mno]
  • 7个匹配项[pqrs]
  • 8个匹配项
  • 和9场比赛[wxyz]

例子:

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

运行功能后,您可以按所需的任何方式打印它。

规则:

  • 标准漏洞无效
  • 您必须返回某些内容,即使它是null/ 如果您不返回任何内容,nil
    Javascript也将返回undefined,因此此规则。
  • 您不能使用或重新实现其他人的答案,也不能复制我的实现。
  • 对于Javascript,您可以假定浏览器已经打开,并且auto元素的innerText/ textContent将作为第二个参数传递
  • 对于已编译的语言,不能将特殊参数传递给编译器
  • 您可以通过编译器参数接收文件名
  • 变量,宏,全局变量,常量,非标准类以及在函数内部传递其他值的所有排序将被视为无效。
  • 在Javascript中,没有关键字的变量var会使您的代码无效
  • 您的函数将被命名 f
  • 您只能并且在函数上只有2个参数
  • 尝试将代码保持在500秒以下。
  • 您不必担心空格
  • 您只能使用ASCII可打印字符。
    例外是使用不可打印字符的语言(APL和空白是两个示例)。

得分:

  • 赢得的最低字节数
  • 您的答案中包含无效的ASCII可打印字符,将被视为使用UTF-32进行编码的答案。编码
    异常会导致您的答案被字符计数。
  • 只有函数体很重要,不要在函数体之外做其他任何事情
  • 如果您根据邻域或最常见的单词建立预测系统,则可获得-30%的奖金
  • 如果您只返回与第一个数字相对应的每个字母的前5个匹配项,则可获得-20%的奖金(例如:245将返回5个以'a'开头的单词,5个以'b'开头的单词和5个以'c'开头的单词)。

这是使用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);
}

要运行它,请打开列表链接并运行,例如:

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

此示例已经过测试,并且可以在Windows 7 Home Edition 64位的Opera 12.17 64位下运行。


程序的第二个参数是一个包含单词或单词列表本身的文件名吗?
Optimizer

@MartinBüttnerUTF-8并不公平(它仍然将ASCII字符视为1字节),但是我更改了规则。
Ismael Miguel

@Optimizer第二个参数是单词列表。如果需要,可以在编译器参数上传递文件名并读取文件。但是唯一重要的是功能体。
Ismael Miguel

@MartinBüttner通过以ASCII计数,它被计为字节。您想让我说APL代码将有1个字节,大小为8位吗?
Ismael Miguel 2014年

2
-1适用于不适当的限制
AJMansfield

Answers:


3

CJam,28个字节

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

以以下形式输入 "<number>" [<list of words>]

例:

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

输出:

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

目前暂无任何奖金。

在此处在线尝试代码,但要进行实际时间测量,请在Java编译器上运行

请注意,CJam代表空列表,例如 ""

要将原始单词列表转换为CJam列表,请使用以下代码,并将单词列表作为输入:

qN/p

“您将收到一个字符串形式的1个电话号码,以及带有单词列表的文本文件的内容”->您能否在其他块上实现所需的代码以将文件读入可用列表?
Ismael Miguel

@IsmaelMiguel您的意思不是该代码的一部分,而是将列表转换为正确格式的辅助代码?
Optimizer

究竟。您的代码不足以证明它可以使用单词列表作为提供的示例。但是无论如何我都赞成,我只想要那个帮助代码。
Ismael Miguel 2014年

您可以将其添加到答案中吗?作为编辑,在不同部分
Ismael Miguel

究竟。我就是这个意思!让我们看看你能不能进一步优化它
伊斯梅尔·米格尔

2

爪哇:395

这将基于每个数字允许的字母形成一个正则表达式模式,然后在末尾附加。*以匹配以下任何字符。

这是高尔夫球版:

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

这是可读性高的版本

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

您的代码违反规则7:“变量,宏,全局变量,常量,非标准类以及所有在函数内部传递其他值的排序将被视为无效。” 这有点违反规则3:“您不能使用或重新实现其他人的答案或复制我的实现。”但是,在您的代码上还是有争议的。而且它还违反了规则9:“您的函数将被命名为f”。
Ismael Miguel 2014年

@IsmaelMiguel糟糕。通过在函数内部移动常量,可以轻松地确定规则7。我只是将其拉到函数之外以获得更好的编程风格。规则9也很容易解决。我承认我没有阅读您的答案,所以我没有刻意尝试复制它。如果您认为比赛太接近了,我可以删除我的答案。
Brian J

您的回答是正确的。您的代码中有一个错误。最后一个常数(([W-Zw-z)])应该是([W-Zw-z])。而且在代码高尔夫上,您不必担心编程风格和良好实践:您的代码必须简单地使用所需的参数来完成。如果您查看我的回答,将会看到以下行:$s=[2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz];。这是PHP中可怕的“犯罪”。基本上,我是在强迫PHP将不存在的常量转换为字符串。这是完全可以接受的。您还将看到,$t在使用变量之前,我甚至没有将其设置为数组
Ismael Miguel 2014年

@IsmaelMiguel很好地抓住了正则表达式错误。感谢您指出。明天我会尝试打高尔夫球。也许可以在此站点上找到一些Java示例。
布莱恩J

我不是Java程序员,但我告诉了您一些事情。您可以检查codegolf.stackexchange.com/questions/6671/…以获得一些提示。一般技巧包括删除无用的空格(换行符,空格,制表符),一个字母长的变量名,并尽一切可能减小代码大小。
Ismael Miguel 2014年

1

C#.NET 4.5 235

这应该工作:

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

欢迎来到PPCG。您的代码可以运行,但是您仍然需要减少很多代码。通过删除所有无用的空格(空格,制表符,换行符),我设法将您的代码减少到167个字节。我敢肯定,此代码可以减少很多。我建议阅读codegolf.stackexchange.com/questions/173/…以缩短您的代码。为了帮助您一点点,单词列表是一个由换行符分隔的字符串,您似乎假设已经可以在其中使用a foreach了。如果您已经希望使用它IEnumerable,请包括外部使用的代码
Ismael Miguel

@IsmaelMiguel TY我会看的。列表是IEnumerable,我发布的内容之外没有任何代码。
Chaossie 2014年

如果看一下函数的规范,您将看到第二个参数也是一个字符串。(引用:“您将收到一个字符串形式的1个电话号码,以及带有单词列表的文本文件的内容(不要采用特定的换行符样式。)。”)并且您的avar 上有1个无用的空格。
Ismael Miguel 2014年

我注意到您的问题有所改善,我给了您好评。但是您仍然可以在avar 上保存一个字节。但我确实看到了明显的改进!保持良好的工作。
Ismael Miguel

1

Python 2(155字节)

还应该在Python 3中使用适当的替换项(string-> bytesb字符串前缀等)工作。

我不确定maketrans在函数外进行调用是否被认为是“公平的”。如果不是,则该函数为134个字节,并且移入了其中。

编辑:从一个愚蠢的监督中删除了一个字节。

具有prepare maketrans,67个字节:

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

随着maketrans身体,134字节:

from string import maketrans

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

随着importmaketrans身体,155字节:

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

测试电话:

print f('9999',open('words.txt','rt').read())

maketrans是函数体的一部分。您应该移动它。我不知道是否有可能,但是您可以尝试直接使用import。我想我在某处看到了它……但是您的代码确实很棒!
Ismael Miguel 2014年

您是要移动导入内容调用身体吗?是的,我认为也可以做到。
criptych与Monica站在2014年

我在想t=(from stirng import maketrans)([...])。我什至不知道是否有可能。但是也许您可以使用from string import as x t=x([...])我不确定是否也可以使用它:/
Ismael Miguel 2014年

正确的版本是最后一个。但是我认为答案是可以接受的。为+1 __import__('string').maketran
Ismael Miguel 2014年

好,谢谢。我已删除了无效答案。
criptych与Monica站在2014年

0

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

好吧,这是一个很大的答案,但是很好。

我希望这能吸引更多人回答。

此功能要求读取原始内容。

这是代码:

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

通过验证字母是否在允许的字母列表中来进行工作。

示例:输入36将检查1abc单词的第一个字母和1def第二个字母。

我附加了1它,因此它不会检查字母是否在第1个位置(该字母将返回0并且结果为false)。if(!strpos(1..$s[$c],$v[$i]))if(!strpos($c.$s[$c],$v[$i]))将具有相同的效果,但第一种混淆更多,我喜欢它。

否则,将删除单词。

没有剩余的单词,它将返回一个空数组。

要在线测试,请访问http://writecodeonline.com/php/并创建一个简单的变量,其中一个单词表示line。

一个可测试的例子:

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

这应该输出:

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

要使用较旧的php版本,请替换$s=[2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz];$s=array(2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz);


对于20%的奖金:

为了减少代码,我简单地添加了代码||$t[$v[0]]++>4,该代码检查了使用第一个字母的次数。

在php中,$t不需要定义,有助于减少37.2字节的大块。

若要查看此效果,请使用以下变量作为第二个参数:

$lines=<<<WORDS
one
two
three
four
five
six
seven
eight
nine
ten
twelve
time
tutor
test
truth
WORDS;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.