Код гольф: найди все анаграммы - PullRequest
16 голосов
/ 02 апреля 2010

Слово - это анаграмма , если буквы в этом слове могут быть переставлены в другое слово.

Задача:

  • Самый короткий исходный код по количеству символов, чтобы найти все наборы анаграмм по заданному списку слов.
  • Пробелы и новые строки должны учитываться как символы
  • Используйте код линейки

    --------- 10 -------- 20 -------- 30 -------- 40 -------- 50- ------- 60 -------- 70 -------- 80 -------- 90 -------- 100 ------ -110 ------- 120

Введите:

a список слов из стандартного ввода, каждое слово которого отделено новой строкой.

, например

A
A's
AOL
AOL's
Aachen
Aachen's
Aaliyah
Aaliyah's
Aaron
Aaron's
Abbas
Abbasid
Abbasid's

Выход:

Все наборы анаграмм, каждый из которых отделен отдельной строкой.

Пример выполнения:

./anagram < words
marcos caroms macros
lump's plum's
dewar's wader's
postman tampons
dent tend
macho mocha
stoker's stroke's
hops posh shop
chasity scythia
...

У меня есть решение на 149 символов perl, которое я опубликую, как только несколько человек опубликуют :)

Веселись!

РЕДАКТИРОВАТЬ: Уточнения

  • Предположим, что анаграммы нечувствительны к регистру (т. Е. Буквы в верхнем и нижнем регистре эквивалентны)
  • Должны быть напечатаны только комплекты с более чем 1 элементом
  • Каждый набор анаграмм должен быть напечатан только один раз
  • Каждое слово в наборе анаграмм должно встречаться только один раз

РЕДАКТИРОВАТЬ 2: Больше разъяснений

  • Если два слова отличаются только заглавными буквами, они должны быть объединены в одно и то же слово, и вам решать, какую схему использования заглавных букв использовать в свернутом слове
  • наборы слов должны заканчиваться только новой строкой, если каждое слово каким-либо образом отделено, например, запятая или пробел является действительным. Я понимаю, что в некоторые языки встроены быстрые методы печати массивов, так что это позволит вам воспользоваться этим, если он не выводит разделенные пробелами массивы.

Ответы [ 8 ]

12 голосов
/ 02 апреля 2010

Perl, 59 символов

chop,$_{join'',sort split//,lc}.="$_ "for<>;/ ./&&say for%_

Обратите внимание, что для этого требуется Perl 5.10 (для функции say).

12 голосов
/ 02 апреля 2010

Powershell, 104 97 91 86 83 знака

$k=@{};$input|%{$k["$([char[]]$_|%{$_+0}|sort)"]+=@($_)}
$k.Values|?{$_[1]}|%{"$_"}

Обновление для нового требования (+8 символов):

Чтобы исключить слова, которые отличаются только заглавными буквами, мы могли бы просто удалить дубликаты (без учета регистра) из списка ввода, то есть $input|sort -u, где -u обозначает -unique. sort по умолчанию не учитывает регистр:

$k=@{};$input|sort -u|%{$k["$([char[]]$_|%{$_+0}|sort)"]+=@($_)} 
$k.Values|?{$_[1]}|%{"$_"} 

Объяснение [char[]]$_|%{$_+0}|sort -части

Это ключ для записи хеш-таблицы, в которой хранятся анаграммы слова. Мое первоначальное решение было: $_.ToLower().ToCharArray()|sort. Затем я обнаружил, что мне не нужно ToLower() для ключа, так как поиск по хеш-таблице не зависит от регистра.

[char[]]$_|sort было бы идеально, но сортировка символов для ключа должна выполняться без учета регистра (в противном случае Cab и abc будут храниться под разными ключами). К сожалению, sort не учитывает регистр символов (только для строк).

Нам нужен [string[]][char[]]$_|sort, но я нашел более короткий способ преобразования каждого символа в строку, который заключается в конкатенации чего-то еще с ним, в данном случае целое число 0, следовательно, [char[]]$_|%{$_+0}|sort. Это не влияет на порядок сортировки, и фактический ключ в итоге выглядит примерно так: d0 o0 r0 w0. Это не красиво, но это делает работу :)

5 голосов
/ 02 апреля 2010

Haskell, 147 символов

предыдущие размеры: 150 159 символы

import Char
import List
x=sort.map toLower
g&a=g(x a).x
main=interact$unlines.map unwords.filter((>1).length).groupBy((==)&).sortBy(compare&).lines

Эта версия на 165 символов удовлетворяет новым, уточненным правилам:

import Char
import List
y=map toLower
x=sort.y
g&f=(.f).g.f
w[_]="";w a=show a++"\n"
main=interact$concatMap(w.nubBy((==)&y)).groupBy((==)&x).sortBy(compare&x).lines

Эта версия обрабатывает:

  1. Слова на входе, которые отличаются только регистром, должны учитываться только как одно слово
  2. Выходные данные должны составлять одну анаграмму на строку, но допускается дополнительная пунктуация
4 голосов
/ 02 апреля 2010

Рубин, 94 символа

h={};(h[$_.upcase.bytes.sort]||=[])<<$_ while gets&&chomp;h.each{|k,v|puts v.join' 'if v.at 1}
3 голосов
/ 02 апреля 2010

Python, 167 символов, включает ввод / вывод

import sys
d={}
for l in sys.stdin.readlines():
 l=l[:-1]
 k=''.join(sorted(l)).lower()
 d[k]=d.pop(k,[])+[l]
for k in d:
 if len(d[k])>1: print(' '.join(d[k]))

Без ввода кода (т. Е. Если мы предположим, что список слов уже есть в списке w), это всего 134 символа:

d={}
for l in w:
 l=l[:-1]
 k=''.join(lower(sorted(l)))
 d[k]=d.pop(k,[])+[l]
for k in d:
 if len(d[k])>1: print(' '.join(d[k]))
2 голосов
/ 02 апреля 2010

C ++, 542 символа

#include <iostream>
#include <map>
#include <vector>
#include <boost/algorithm/string.hpp>
#define ci const_iterator
int main(){using namespace std;typedef string s;typedef vector<s> vs;vs l;
copy(istream_iterator<s>(cin),istream_iterator<s>(),back_inserter(l));map<s, vs> r;
for (vs::ci i=l.begin(),e=l.end();i!=e;++i){s a=boost::to_lower_copy(*i);
sort(a.begin(),a.end());r[a].push_back(*i);}for (map<s,vs>::ci i=r.begin(),e=r.end();
i!=e;++i)if(i->second.size()>1)*copy(i->second.begin(),i->second.end(),
ostream_iterator<s>(cout," "))="\n";}
2 голосов
/ 02 апреля 2010

AWK - 119

{split(toupper($1),a,"");asort(a);s="";for(i=1;a[i];)s=a[i++]s;x[s]=x[s]$1" "}
END{for(i in x)if(x[i]~/ .* /)print x[i]}

У AWK нет функции join, как у Python, или она могла бы быть короче ...

Предполагается, что прописные и строчные буквы различаются.

1 голос
/ 02 апреля 2010

Python, O (n ^ 2)

import sys;
words=sys.stdin.readlines()
def s(x):return sorted(x.lower());
print '\n'.join([''.join([a.replace('\n',' ') for a in words if(s(a)==s(w))]) for w in words])
...