Current section
Files
Jump to
Current section
Files
lib/comparer.ex
defmodule Pair2.Comparer do
@moduledoc """
Core functions for comparing two values or maps and returning a similarity value between 0.0 and 1.0.
"""
@doc """
Scores the similarity of two maps based on a list of rules.
Returns score that is >= 0.0.
"""
def compare_maps(map_l, map_r, rules) do
Enum.reduce(rules, 0.0, fn(rule, acc) ->
{l_val, r_val} = case Map.has_key?(rule, :left_attr) do
true -> {Map.get(map_l, rule.left_attr), Map.get(map_r, rule.right_attr)}
false -> {Map.get(map_l, rule.attr), Map.get(map_r, rule.attr)}
end
score = compare(l_val, r_val, rule)
case score >= rule.min_match do
true -> acc + (score * rule.weight)
false -> acc
end
end)
end
@doc """
Based on argument types and values, selects one of the compare_* methods
to use for comparing x and y.
"""
def compare(x, y, rule) do
cond do
rule.fun != nil -> compare_with_fun(x, y, rule.fun)
is_bitstring(x) -> compare_strings(x, y)
is_number(x) -> compare_nums(x, y)
is_map(x) -> compare_days(x, y, rule.max_days)
is_nil(x) -> 0.0
true -> raise "no comparison available for x:#{x} and y:#{y}"
end
end
@doc """
Compares the absolute difference between numbers x and y and returns the similarity
expressed as the difference divided by the larger of x or y.
Return value is between 0.0 and 1.0.
## Examples
iex> Compare.compare_nums(5, 10)
0.5
"""
def compare_nums(x, y) do
cond do
x == y -> 1.0
x > y -> (x - abs(x - y)) / x
y > x -> (y - abs(x - y)) / y
end
end
def compare_strings(x, y) do
case x == y do
true -> 1.0
false -> 0.0
end
end
@doc """
Compares the absolute difference between dates x and y and returns the similarity
expressed as the difference in days divided by the max_days argument.
Return value is between 0.0 and 1.0.
"""
def compare_days(x, y, max_days) do
diff = abs(Timex.diff(x, y, :days))
cond do
diff == 0 -> 1.0
diff > max_days -> 0.0
diff <= max_days -> (max_days - diff) / max_days
end
end
@doc """
Compares x and y using the match criteria
defined in the fun argument. Function should return value between 0.0 and 1.0
"""
def compare_with_fun(x, y, fun) do
fun.(x, y)
end
end