Реализовать t9-подобную функциональность

10

Ваша задача сегодня - реализовать функциональность, подобную t9 .

Вы реализуете функцию, которая будет иметь только 2 параметра.
Вы получите 1 номер телефона в строке и содержимое текстового файла со списком слов (не используйте конкретный стиль перевода строки).
Вы можете использовать ссылку https://raw.githubusercontent.com/eneko/data-repository/master/data/words.txt, чтобы проверить функциональность, или использовать /usr/share/dict/words(проверьте текстовый файл со списком слов [закрыто], чтобы узнать больше Информация).

Вы можете предположить, что вы всегда получите как минимум 2 номера.

Учитывая число, вы будете читать из списка слов и возвращать слова, начинающиеся с букв, сопоставляемых с этими словами. Это означает, что ввод должен состоять только из цифр от 2 до 9.
Вы можете делать все, что захотите, если получите неверный ввод.

Если совпадение не найдено, вы можете вернуть пустой список, null/ nilили 0.

Помните, что клавиши мобильного телефона сопоставлены с их эквивалентными символами:

  • 0 и 1 недействительны
  • 2 матча [abc]
  • 3 совпало [def]
  • 4 матча [гхи]
  • 5 матчей [jkl]
  • 6 матчей [мно]
  • 7 матчей [pqrs]
  • 8 матчей [tuv]
  • и 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 вы можете предположить, что браузер будет уже открыт и что innerText/ textContentиз автоматического элемента будет передан в качестве второго параметра
  • Для скомпилированных языков вы не можете передавать специальные аргументы компилятору
  • Вы можете получить имя файла через аргументы компилятора
  • Переменные, макросы, глобальные переменные, константы, нестандартные классы и все виды, передающие другие значения внутри функции, будут считаться недействительными.
  • В Javascript переменные без ключевого слова varделают ваш код недействительным
  • Ваша функция будет названа f
  • Вы можете только и только иметь 2 аргумента в вашей функции
  • Постарайтесь, чтобы ваш код работал менее 500 секунд.
  • Вам не нужно беспокоиться о пробелах
  • Вы должны использовать только печатные символы ASCII .
    Исключением являются языки, которые используют только непечатаемые символы (2 примера - APL и пробелы).

Подсчет очков:

  • Наименьшее количество выигранных байтов
  • Наличие в вашем ответе недопустимых печатных символов ASCII будет засчитываться как кодировка ответа в UTF-32
    . Исключение из кодировки заставит ваш ответ быть посчитанным символами .
  • Подсчитывает только тело функции, не считайте ничего, что вы делаете вне ее
  • Бонус -30%, если вы делаете систему прогнозирования на основе соседства или наиболее распространенных слов
  • Бонус -20% в размере, если вы возвращаете только первые 5 совпадений для каждой буквы, соответствующей первому числу (например: 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 "]

Этот пример был протестирован и работает под 64-битной версией Opera 12.17 на 64-битной Windows 7 Home Edition.

Исмаэль Мигель
источник
Является ли второй аргумент программы именем файла, содержащим слова или сам список слов?
Оптимизатор
@ MartinBüttner UTF-8 не является несправедливым (он все еще считает символы ASCII равными 1 байту), но я изменил правило.
Исмаэль Мигель
@Optimizer Второй аргумент - это список слов. Вы можете передать имя файла через аргумент компилятора и прочитать файл, если хотите. Но единственное, что имеет значение, это тело функции.
Исмаэль Мигель
@ MartinBüttner Подсчитывая как ASCII, он считается как байты. Вы хотите, чтобы я сказал, что код APL будет иметь 1 байт размером 8 бит?
Исмаэль Мигель
2
-1 за несоответствующие ограничения
AJMansfield

Ответы:

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 номер телефона в строке и содержимое текстового файла со списком слов» -> можете ли вы внедрить в другом блоке необходимый код для чтения файла в пригодный для использования список?
Исмаэль Мигель
@IsmaelMiguel Вы имеете в виду не часть этого кода, а просто вспомогательный код для преобразования списка в правильный формат?
Оптимизатор
Точно. Какой код недостаточно, чтобы доказать, что он может использовать список слов в качестве примеров. Но я все равно проголосовал, я просто хотел этот вспомогательный код.
Исмаэль Мигель
Вы можете добавить это к ответу? Как редактировать, в другой части
Исмаэль Мигель
Точно. Это то, о чем я говорю! Давайте посмотрим, сможете ли вы оптимизировать его еще больше
Исмаэль Мигель
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».
Исмаэль Мигель
@IsmaelMiguel Упс. Правило 7 может быть легко исправлено путем перемещения константы внутри функции. Я просто вытащил его за пределы функции для лучшего стиля программирования. Правило 9 также легко исправить. Признаюсь, я не читал ваш ответ, поэтому я не пытался его намеренно копировать. Я могу удалить свой ответ, если вы думаете, что он слишком близко для конкурса.
Брайан Дж
Ваш ответ в порядке. У вас есть ошибка в вашем коде. По последней константе ( ([W-Zw-z)]) это должно быть ([W-Zw-z]). И в Code-golf вам не нужно беспокоиться о стилях программирования и хороших методах: ваш код должен просто выполнять свою работу с необходимыми параметрами. Если вы отметите мой ответ, вы увидите следующую строку: $s=[2=>abc,def,ghi,jkl,mno,pqrs,tuv,wxyz];. Это ужасное «преступление» в PHP. В основном я заставляю PHP преобразовывать несуществующие константы в строки. Это вполне приемлемо. Вы также увидите, что я даже не устанавливаю переменную $tв массив, прежде чем использовать ее как таковую
Исмаэль Мигель
@IsmaelMiguel Хорошо поймал ошибку регулярного выражения. Спасибо за указание на это. Я попытаюсь сыграть в гольф завтра; может быть, найти некоторые примеры Java на этом сайте.
Брайан Дж
Я не программист Java, но я скажу вам кое-что. Вы можете проверить codegolf.stackexchange.com/questions/6671/… чтобы получить несколько советов. Общие советы включают удаление бесполезных пробелов (переводы строк, пробелы, табуляции), имен переменных длиной в одну букву и делают все возможное, чтобы максимально уменьшить размер кода.
Исмаэль Мигель
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;}
Chaossie
источник
Добро пожаловать в PPCG. Ваш код будет работать, но вам все равно нужно значительно его уменьшить. Удалив все бесполезные пробелы (пробелы, табуляции, новые строки), мне удалось сократить ваш код до 167 байт. Этот код может быть уменьшен намного больше, я уверен в этом. Я рекомендую прочитать codegolf.stackexchange.com/questions/173/… чтобы еще больше сократить ваш код. Чтобы вам немного помочь, список слов - это строка, разделенная символами новой строки, и вы, кажется, предполагаете, что в ней уже можно использовать a foreach. Если вы ожидаете, что это уже будет IEnumerable, включите код, используемый снаружи
Исмаэль Мигель
@IsmaelMiguel TY Я посмотрю на это. Список IEnumerable нет кода вне того, что я опубликовал.
Chaossie
Если вы посмотрите на спецификацию функции, вы увидите, что 2-й параметр также является строкой. (Цитата: «Вы получите 1 номер телефона в строке и содержимое текстового файла со списком слов (не используйте конкретный стиль новой строки).») И у вас есть 1 бесполезный пробел в вашей aпеременной.
Исмаэль Мигель
Я заметил улучшения в вашем вопросе и дал вам голос. Но вы все равно можете сохранить байт в своей aпеременной. Но я действительно вижу заметные улучшения! Продолжайте хорошую работу.
Исмаэль Мигель
1

Python 2 (155 байт)

Также должен работать в Python 3 с соответствующими заменами ( string-> bytes, bпрефикс на строки и т. Д.).

Я не был уверен, что maketransвызов вне функции считается "честным"; если нет, функция составляет 134 байта с перемещением внутрь.

РЕДАКТИРОВАТЬ: Отбросил один байт из-за глупого недосмотра.

С подготовленными maketrans67 байтами:

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

С importи maketransв теле, 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. Я думаю, что где-то видел ... Но ваш код действительно хорош!
Исмаэль Мигель
Вы хотите перенести импорт и позвонить в тело? Да, я думаю, что это тоже можно сделать.
criptych стоит с Моникой
Я думал о t=(from stirng import maketrans)([...]). Я понятия не имею, возможно ли это вообще. Но, может быть, вы можете использовать то, from string import as x t=x([...])что я не уверен, если это тоже возможно: /
Исмаэль Мигель
Правильная версия - последняя. Но ответ как есть, на мой взгляд, приемлем. +1 за __import__('string').maketran.
Исмаэль Мигель
Хорошо, спасибо. Я удалил неправильные ответы.
Криптих стоит с Моникой
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имеет 2-ю букву.

Я добавляю, 1чтобы он не проверял, находится ли буква в 1-й позиции (которая вернется 0и будет оценена false). if(!strpos(1..$s[$c],$v[$i]))или if(!strpos($c.$s[$c],$v[$i]))будет иметь тот же эффект, но 1-е смущает больше, и мне это нравится.

В противном случае будет удалено слово.

Если не осталось слов, он возвращает пустой массив.

Чтобы проверить это онлайн, перейдите на http://writecodeonline.com/php/ и создайте простую переменную со словом для строки.

Тестируемый пример:

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;
Исмаэль Мигель
источник