Current section
Files
Jump to
Current section
Files
lib/jaro.ex
defmodule Jaro do
def jaro_distance(string1, string2)
def jaro_distance(string, string), do: 1.0
def jaro_distance(_string, []), do: 0.0
def jaro_distance([], _string), do: 0.0
def jaro_distance(chars1, chars2) when is_list(chars1) and is_list(chars2) do
len1 = length(chars1)
len2 = length(chars2)
case match(chars1, len1, chars2, len2) do
{0, _trans} ->
0.0
{comm, trans} ->
(comm / len1 + comm / len2 + (comm - trans) / comm) / 3
end
end
defp match(chars1, len1, chars2, len2) do
if len1 < len2 do
match(chars1, chars2, div(len2, 2) - 1)
else
match(chars2, chars1, div(len1, 2) - 1)
end
end
defp match(chars1, chars2, lim) do
match(chars1, chars2, {0, lim}, {0, 0, -1}, 0)
end
defp match([char | rest], chars, range, state, idx) do
{chars, state} = submatch(char, chars, range, state, idx)
case range do
{lim, lim} -> match(rest, tl(chars), range, state, idx + 1)
{pre, lim} -> match(rest, chars, {pre + 1, lim}, state, idx + 1)
end
end
defp match([], _, _, {comm, trans, _}, _), do: {comm, trans}
defp submatch(char, chars, {pre, _} = range, state, idx) do
case detect(char, chars, range) do
nil ->
{chars, state}
{subidx, chars} ->
{chars, proceed(state, idx - pre + subidx)}
end
end
defp detect(char, chars, {pre, lim}) do
detect(char, chars, pre + 1 + lim, 0, [])
end
defp detect(_char, _chars, 0, _idx, _acc), do: nil
defp detect(_char, [], _lim, _idx, _acc), do: nil
defp detect(char, [char | rest], _lim, idx, acc), do: {idx, Enum.reverse(acc, [nil | rest])}
defp detect(char, [other | rest], lim, idx, acc),
do: detect(char, rest, lim - 1, idx + 1, [other | acc])
defp proceed({comm, trans, former}, current) do
if current < former do
{comm + 1, trans + 1, current}
else
{comm + 1, trans, current}
end
end
end