Один лист своп


18

Найбільший форум в Інтернеті під назвою postcount ++ вирішив створити нову гру на форумі. У цій грі мета - розмістити слово, але в слові має бути додана, видалена або змінена одна буква. Ваш бос хотів, щоб ви написали програму, яка набирає слова, і словник UNIX, коли ви працюєте для компанії, яка має більш розумний форум з більш розумними іграми на форумі, і хоче знищити конкуренцію (ей, це ваш бос, не варто обговоріть з ним, ви все одно отримаєте багато грошей на роботі).

Ваша програма отримає два аргументи, слово та словник. Оскільки користувач, що управляє програмою (так, користувач, ваша компанія не має ресурсів для запуску ботів), не є ідеальним, вам слід нормалізувати випадок в обох випадках. Слова в словнику можуть мати літери ASCII (як великі, так і малі, але їх слід ігнорувати під час порівняння), тире, апострофи та непослідовні пробіли посередині. Вони не будуть довше 78 символів. Ви повинні вивести список слів, які були б прийняті в грі, щоб порушити задоволення від людей, які думають про слова вручну.

Це приклад вашої очікуваної програми, перевірка на схожі слова golf.

> ./similar golf /usr/share/dict/words
Goff
Wolf
gold
golfs
goof
gulf
wolf

Список /usr/share/dict/words- це список слів з переривом рядків після кожного. Ви можете легко прочитати це, наприклад, за допомогою fgets ().

У компанії, в якій ви працюєте, немає багато перфокарт (так, це 2014 рік, і вони все ще використовують перфокарти), тому не витрачайте їх. Напишіть якомога коротшу програму. О, і вас попросили не використовувати вбудовані чи зовнішні реалізації відстані Левенштейна або будь-який подібний алгоритм. Щось про Not Invented Here або backdoors, що, очевидно, постачальник вставлений на мову (у вас немає доказів цього, але не обговорюйте з вашим начальником). Тож якщо ви хочете відстань, вам доведеться реалізувати це самостійно.

Ви можете вільно користуватися будь-якою мовою. Навіть з перфокартами компанія має доступ до найсучасніших мов програмування, таких як Cobol Ruby або Haskell або будь-що, що вам потрібно. У них навіть є GolfScript, якщо ви думаєте, що це добре для обробки струнами (я не знаю, можливо ...).

Переможець отримує від мене 15 балів репутації та, мабуть, багато інших балів від громади. Інші хороші відповіді отримають 10 балів, а також бали від громади. Ви чули, що очки нічого не варті, але, швидше за все, вони замінять долари в 2050 році. Це не було підтверджено, але все-таки хороша ідея отримати бали.


6
Ми не повинні "використовувати вбудовані чи зовнішні реалізації відстані Левенштейна або будь-який подібний алгоритм"? Там іде рішення з 30 символів Mathematica.
Майкл Стерн

@MichaelStern та аналогічно короткий пітон, що використовує нечітке співставлення цієї бібліотеки з регулярними виразками
Мартін Ендер

2
Майже те саме, що і codegolf.stackexchange.com/questions/6939/… .
Говард

"такі як Рубі чи Хаскелл" - добре, я це зрозумів, ви хочете, щоб я брав участь.
Джон Дворак

Надайте кращий приклад, щоб усі типи змін з’являлися або люди продовжували подавати неправильні алгоритми.
швейцарський

Відповіді:


4

GolfScript, 59 символів

{32|}%"*"%.|(:w;{:x,),{:^[x>.1>]{.[^w=]\+}%{^x<\+w=},},},n*

Звичайно, GolfScript чудово підходить для маніпуляцій зі струнами!

Те, що в GolfScript не дуже добре, обробляє аргументи файлів вводу / виводу або командного рядка. Таким чином, ця програма розраховує отримати все своє введення через stdin: перший непорожній рядок вважається цільовим словом, а решта повинні містити словник. У системі Unixish ви можете запустити цей код, наприклад, за допомогою:

(echo golf; cat /usr/share/dict/words) | ruby golfscript.rb similar.gs

У моєму вікні Ubuntu Linux вихід цієї команди є:

goff
wolf
gold
golfs
goof
gulf

Зверніть увагу, що всі слова перетворюються на малі регістри, а будь-які дублікати усуваються; таким чином, на відміну від вашої вибірки, шахта не перераховується Wolfта wolfокремо. Виходячи з опису виклику, я вважаю, що це прийнятно.

Крім того, код дійсно повільний, оскільки він використовує досить грубу силу підходу, і не використовує навіть очевидних оптимізацій, таких як перевірка відповідності довжини слова-кандидата довжині цільового слова ± 1. через повний, нефільтрований /usr/share/dict/wordsсписок у ... гм ... Я дам вам знати, коли він закінчиться, гаразд?

Редагувати: Гаразд, це зайняло близько 25 хвилин, але це закінчилося.


+1 для точного уявлення про те, наскільки хороший GolfScript для маніпуляції з рядком (та проведення стринг-маніпуляцій у GolfScript)
PlasmaPower

6

Bash + coreutils, 99 байт

Або я повністю не зрозумів питання (відповідь @ lambruscoAcido дає дуже різні результати ), або це досить просте додаток для регулярного выраження :

for((i=0;i<${#1};i++)){
a=${1:0:i}
b=${1:i+1}
egrep -i "^($a$b|$a.$b|$a.${1:i}|$1.)$" $2
}|sort -u

Вихід:

$ ./s similar.sh гольф / usr / share / dict / слова
Гофф
золото
гольф
гольфи
гуф
затока
вовк
Вовк
$ 

Чи можете ви поясніть, що ${a:b:c} робити?
AL

1
@ n.1 він займає символів у позиціях bдо cзмінноїa

2
@professorfish Close - підрядок довжини, cпочинаючи з позиції b(нульова) від змінної a. Розширення підрядків - одне з розширень параметрів bash
Digital Trauma

2
@DigitalTrauma о, я забув, хоча я продовжую використовувати його в своїх Bash

3

Пітон 3, 291 символ

Дуже відвертий і, таким чином, не дуже розумний. Але з великим смачним генератором клубок і оптимізованою повільністю. Тому що ви не хочете залишати призначений час для обчислення невикористаним, чи не так?

from itertools import*
from sys import*
a=argv[1].lower()
r,l=range,len
n=l(a)
print('\n'.join((b for b in(s.strip()for s in open(argv[2]).readlines())if l(b)>n-2and b.lower()in(''.join(compress(a,(i!=j for j in r(n))))for i in r(n))or n==l(b)and sum(1for i in r(n)if a[i]!=b.lower()[i])<2)))

1
Можна використовувати l=lenта r=rangeзменшити ці функції.
TyrantWave

1

Scala - 403 130

[Оновлено]: повністю оновлено, оскільки попереднє рішення також дозволено для перестановлених літер. Не використовує регулярні вирази або будь-які вбудовані інструменти.

def f(x:String,d:List[String])={for{y<-d;c=(x zip y filter(t=>t._1!=t._2)length);n=y.length-x.length;if c<2&n==0|c==0&n==1}yield y

Безголівки:

def f(x:String, d:List[String]) = {
  for {
    y <- d
    c = (x zip y filter (t=>t._1!=t._2) length)  // #letter changes.
    n = y.length-x.length                        // Difference in word length.
    if c<2 & n==0 | c==0 & n==1
  } yield y
}

Використання:

f("golf", io.Source.fromFile("/usr/share/dict/words").getLines.toList)

@DigitalTrauma Чи можете ви надати приклад для цього питання?
lambruscoAcido

Я зрозумів: я також розглядав усі перестановки листів. Зітхніть - значить, реальність легша. Дякую ...
lambruscoAcido

atechnyне змінює жодної літери. Це рішення робить щось незв'язане з питанням.
Конрад Боровський

+1. виглядає так, що зараз краще відповідає специфікації ;-)
Digital Trauma

Повна програма була б непоганою, а не лише функціонувала.
швейцарський

1

Пітон, 174 символів:

Швидко і до речі.

import re;from sys import*;w=argv[1]
print"\n".join(set(sum([re.findall(r"\b%s%s?[^'\n]?%s\b"%(w[:i],w[i],w[i+1:]),open(argv[2]).read(),re.I)for i in range(len(w))],[]))-{w})

Приклад:

python similar.py golf /usr/share/dict/words

Вихід:

goof
gola
gulf
gold
gol
gowf
goli
Golo
Gulf
goaf
Wolf
Goll
Rolf
wolf
goff
Gold

Я вважаю, що у файлі слів OS X просто більше записів.


Список не повинен включати саме слово, а також він не ігнорує апострофи: у словнику UNIX він також є golf'.
швейцарський

Що ви маєте на увазі, ігноруючи апострофи? Після перечитування підказки я все ще не бачу, до чого ви потрапляєте.
xleviator

Якщо я запускаю ваш код у словнику з golf'ним, він буде надрукований.
швейцарський

Ах, я неправильно прочитав підказку, але це зараз виправлено.
xleviator

0

Хаскелл - 219

import System.Environment
import Data.Char
u@(x:a)%w@(y:b)|x==y=a%b|1>0=1+minimum[a%w,u%b,a%b]
x%y=max(length x)$length y
main=do[w,d]<-getArgs;readFile d>>=mapM putStrLn.filter((==1).(%map toLower w).map toLower).words

0

Ребол - 213

set[i d]split system/script/args" "r:[skip i | i skip]repeat n length? i[append r compose[|(poke s: split i 1 n 'skip s)|(head remove at copy i n)]]foreach w read/lines to-file d[if all[w != i parse w r][print w]]


Ungolfed (з деякими коментарями):

set [i d] split system/script/args " "

; build parse rule
r: [skip i | i skip]       ; RULE - one letter added (prefix and postfix)

; sub-rule for each letter in word
repeat n length? i [
    append r compose [
        | (poke s: split i 1 n 'skip s)     ; RULE - letter changed
        | (head remove at copy i n)         ; RULE - letter removed
    ]
]

foreach w read/lines to-file d [
    if all [w != i parse w r] [print w]
]

Приклад використання (випробуваний у Rebol 3 на OS X Lion):

$ rebol similar.reb golf /usr/share/dict/words
goaf
goff
gol
gola
Gold
gold
goli
Goll
Golo
goof
gowf
Gulf
gulf
Rolf
Wolf
wolf

Нижче наведено parseправило, яке відповідає аналогічним словам гольфу :

[
    skip "golf"
  | "golf" skip
  | skip "o" "l" "f"
  | "olf"
  | "g" skip "l" "f"
  | "glf"
  | "g" "o" skip "f"
  | "gof"
  | "g" "o" "l" skip
  | "gol"
]

-1

Пітон (103):

f=lambda x:[a for a in open('/usr/share/dict/words')if len(x)==len(a)&sum(b!=c for b,c in zip(a,x))==1]

Думаю, досить ефективно, я думаю. Крім того, мені подобається, наскільки добре цей гольф в Python.


Ви не обліковуєте за видалення або додавання символу.
швейцарський
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.