What is a good way to compare structs?

In some tests, we need to compare 2 structs between each other. However when we build

  • the test struct: this is done manually
  data_actions: %{A, B}
  • the core struct, we go through a
data_actions |> Map.from_struct() |> Enum.reduce( ...)

Since OTP 26, Maps aren’t ordered anymore (Taking Control of Map Sort Order in Elixir · The Phoenix Files) so the result is random (in the resulting struct, the data_actions have a random order).

Is there any way to compare a struct recursively, without considering the values order? What is the elixir way to do it clean?

to clarify: you want to compare two maps, not two structs?

concretely yes, but recursively

Not sure I understand the problem? Can you give an example of which comparison is failing?

The == operator does not care about order when comparing maps. This applies for structs too.

%{key1: :equal, key2: :values} == %{key2: :values, key1: :equal}
#=> true
%{key1: :unequal, key2: :values} == %{key2: :values, key1: :equal}
#=> false

For tests, you can just assert map1 == map2 as you would expect.


just adding to that, if you’re talking about tests… if you pattern match you can just look for the stuff you care for in a particular test run… so that works

assert %{field: :i_care_for} = %MyStruct{field: :i_care_for, other_field: :dont_care_about}

Hi @Laurent,

If I understand your problem properly I would like to suggest this approach.

Let’s say we have map_a = %{a: "a", b: "b", c: "c"} and map_b: %{a: "a", b: "b", c: "no_match"}
We could use Enum.reduce_while/3 to iterate through map_a and compare key and value from map_a with the key and value of map_b.

Enum.reduce_while(map_a, true, fn {k, v}, acc ->
  # This statement checks if the key from map_a exists in map_b. if the key exists, also checks the 
  # value of the keys. If it is true, iteration is continued, otherwise it is halted and it will return false
  if v == Map.get(map_b, k) do
    {:cont, acc}
    {:halt, false}

I hope this will help you :upside_down_face:

can you give me some example of map comparison that is failing? It should not be failing even if the order of fields looks different for some reason.


Again, what is wrong with a simple map_a == map_b ?


Absolutely nothing :+1: == operator is the best way to do it. For some reason my brain went for a more complex approach :man_shrugging: