Отличное решение! И самое обидное, что очень эффективное – у нас классический подход через записи 15 секунд работал. Впрочем, это можно будет студентам показать, Pattern Matching работает тут очень хорошо.
Скажите, а почему вот такой вариант не работает? В словаре вроде компаратор используется, но почему-то не хочет сливать разные падежи слов.
type StringsEqualityComparer = class (IEqualityComparer<string>)
class count : integer;
public function Equals(s1,s2 : string) : boolean;
begin
var w := min(s1.Length, s2.Length)-2;
count += 1;
Result := copy(s1,1,w)=copy(s2,1,w);
end;
public function GetHashCode(s : string):integer;
begin
Result := s.GetHashCode;
end;
end;
begin
var w := new System.Net.WebClient();
var ss := w.DownloadString('http://vojnaimir.ru/files/book1.txt');
var q := ss.MatchValues('\b\p{Lu}\w{3,}\b');
var d := new Dictionary<string,integer>(new StringsEqualityComparer());
foreach var x in q do
d[x] := d.Get(x) + 1;
d.OrderByDescending(x->x.Value).Take(10).Print(NewLine);
writeln;
writeln('Компаратор выполнил сравнений : ',StringsEqualityComparer.count);
var cmp := new StringsEqualityComparer();
var s1 := 'Пьер';
var s2 := 'Пьерa';
writeln(s1,' = ',s2,' -> ',cmp.equals(s1,s2));
s2 := 'Андрей';
writeln(s1,' = ',s2,' -> ',cmp.equals(s1,s2));
end.
Да в принципе можно банально взять для GetHashCode первые три-четыре символа строки, этого будет достаточно, и производительность практически не пострадает.
Вот ещё бы научиться оставлять в качестве ключа наиболее встречаемые варианты имени, а не ту форму, которая встретилась первой. Это, видимо, надо сливать все имена в словарь, а потом рассматривать по убыванию частоты появления в тексте, и перегонять в словарик, который выполняет слияние по нашему правилу сравнения.
А пока что вот так:
type StringsEqualityComparer = class (IEqualityComparer<string>)
public function Equals(s1,s2 : string) : boolean;
begin
var w := min(s1.Length, s2.Length)-2;
Result := copy(s1,1,w)=copy(s2,1,w);
end;
public function GetHashCode(s : string):integer;
begin
Result := copy(s,1,4).GetHashCode;
end;
end;
begin
var q := System.Net.WebClient.Create.DownloadString('http://vojnaimir.ru/files/book1.txt').MatchValues('\b\p{Lu}\w{3,}\b');
var d := new Dictionary<string,integer>(new StringsEqualityComparer());
foreach var x in q do
d[x] := d.Get(x) + 1;
d.OrderByDescending(x->x.Value).Take(20).Print(NewLine);
end.