Какой способ сравнить карты в эликсире - PullRequest
4 голосов
/ 06 февраля 2020

Учитывая две большие и разные карты, определенные следующим образом:

Interactive Elixir (1.9.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> m1 = Map.new(1..1_000_000 |> Enum.map(&{&1, &1})); :ok
:ok
iex(2)> m2 = Map.new(2..1_000_000 |> Enum.map(&{&1, &1})); :ok
:ok

требуется значительная разница во времени при сравнении их с использованием ==/2 и Map.equal?/2

iex(3)> :timer.tc(fn -> m1 == m2 end)
{21, false}
iex(4)> :timer.tc(fn -> Map.equal?(m1, m2) end)
{20487, false}

Что такое причина этой разницы во времени между ==/2 и Map.equal?/2, и что использовать?

Эквивалентно, что использовать между ==/2 и ===/2? (потому что Map.equal?/2 звонит на ===/2, см. здесь )

Спасибо

1 Ответ

5 голосов
/ 06 февраля 2020

Действительно, Map.equal?/2 просто делегирует Kernel.===/2.

Kernel.===/2 делегирует :erlang."=:="/2 и Kernel.==/2 делегирует :erlang."=="/2. Последний сравнивает числа , тогда как первый сравнивает значения и типы .

Рассмотрим следующий пример.

%{1 => 1} == %{1 => 1.0}
#⇒ true

%{1 => 1} === %{1 => 1.0}
#⇒ false

При этом Kernel.===/2 следует сравнить со всеми значениями . OTOH, Erlang / OTP ссылка явно заявляет , что

Карты упорядочены по размеру, две карты одинакового размера сравниваются по ключам в порядке возрастания сроков а затем по значениям в ключевом порядке. В картах целочисленные типы порядка ключей считаются меньшими, чем типы с плавающей запятой.

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


Подводя итог, я бы посчитал эту разницу во времени ошибкой в ​​реализации :erlang."=:="/2, о которой следует сообщить команде Erlang .

...