Qqwy

Qqwy

TypeCheck Core Team

MapDiff: A small library that computes the difference between two maps

Hello everyone,

I wrote a small library today called MapDiff.
It returns a map listing the (smallest amount of) changes to get from map_a to map_b:

iex> foo = %{a: 1, b: 2, c: %{d: 3, e: 4, f: 5}}
iex> bar = %{a: 1, b: 42, c: %{d: %{something_else: "entirely"}, f: 10}}
iex> MapDiff.diff(foo, bar)
%{changed: :map_change,
  value: %{a: %{changed: :equal, value: 1},
    b: %{added: 42, changed: :primitive_change, removed: 2},
    c: %{changed: :map_change,
      value: %{d: %{added: %{something_else: "entirely"},
      changed: :primitive_change, removed: 3},
    e: %{changed: :removed, value: 4},
    f: %{added: 10, changed: :primitive_change, removed: 5}}}}}

This is mainly useful if you have two maps describing the state of something, where
replacing all of the old state and then filling in the new is too slow, which means that only
replacing the things that actually are changed is better.

It is similar to what Elm does to represent its output to the HTML Domain Object Model. The reason I wrote MapDiff is that I am planning on writing a library that wraps Erlang’s wxWidgets bindings in a similar way that Elm wraps the HTML DOM, which would allow people to write GUIs in a Functional style (wxWidgets itself is Object-Oriented). Does this sound like a huge undertaking? Yes! Let’s see how far I can get with it :grin:


Anyhow, MapDiff is a very small and basic library, but it might be useful for some other people as well, so I thought I’d publish it on Hex.pm :slight_smile: . Feedback is of course greatly appreciated.

Most Liked

Qqwy

Qqwy

TypeCheck Core Team

All right! MapDiff is updated to 1.1.0.
The single but important new feature: Supporting structs in a meaningful way.

  • comparing two structs of the same type returns a map of fields that were changed.
  • comparing two structs of a different type returns a primitive_change where the whole of the old struct was replaced for the whole of the new struct.

Examples:

iex> MapDiff.diff(%Foo{}, %Foo{a: 3})
%{changed: :map_change, struct_name: Foo,
  value: %{a: %{added: 3, changed: :primitive_change, removed: 1},
    b: %{changed: :equal, value: 2}, c: %{changed: :equal, value: 3}}}

When comparing two different kinds of structs, this of course results in a :primitive_change, as they are simply considered primitive data types:

iex> MapDiff.diff(%Foo{}, %Bar{})
%{added: %Bar{a: "foo", b: "bar", z: "baz"}, changed: :primitive_change,
  removed: %Foo{a: 1, b: 2, c: 3}}
Qqwy

Qqwy

TypeCheck Core Team

By the way,

The library consists of one small module (or actually, one single public function, even).

The code still uses quite a few if/else statements inside this function definition. Is there a way to make this code even more Elixir-idiomatic?

lambdadevfr

lambdadevfr

I was in a company where we had a huge usage of such a library. It was mostly used for tests.
Basically a test (in erlang) was written:
my_test() ->
Expected = {this, that, [etc]}
Result = module:call(params…)
diff (Expected, Result).

When a test failed you could very quickly see the difference between what was expected and the result. Super usefull

andre1sk

andre1sk

It’s possible to do same things with functions and pattern matches something like
https://github.com/andre1sk/elixir_map_diff/blob/refactor/lib/map_diff.ex

Qqwy

Qqwy

TypeCheck Core Team

Version 1.2 was just released, which also allows comparisons between non-map (and non-struct) types. It is mostly useful when having a default value such as e.g. nil before you construct a map for the first time.

Where Next?

Popular in Libraries Top

OvermindDL1
Been making an MLElixir thing (not released yet…) for fun in spare time in the past day. I’m just trying to see how much I can get an ML...
132 13487 106
New
dbern
I’m excited to announce that TaxJar has developed and open-sourced DateTimeParser. We developed it because we found a need to parse user ...
New
pkrawat1
Hey guyz We at @aviabird are working on a payment library in elixir/phoenix. We are targeting March 2018 to add 56 Gateways to it. Have...
New
deadtrickster
I’ve just released stable versions of my Prometheus Elixir libs: Elixir client [docs]; Ecto collector [docs]; Plugs instrumenter/Export...
New
mathieuprog
Hello :wave: Allow me to introduce you to Tz, an alternative time zone database support to Tzdata. Why another library? First and fore...
New
Crowdhailer
The latest release of Ace (0.10.0) includes serving content over HTTP/2. I have started writing a webserver to teach my self more about...
New
nikokozak
Hello all, I’ve been working on Svonix - a library for quickly integrating Svelte components into Phoenix views. It’s a much-needed succ...
New
wfgilman
I’ve cleaned up and open sourced three financial libraries I was using for my company. They are bindings for the APIs of these three comp...
New
mbuhot
EctoJob A transactional job queue built with Ecto, PostgreSQL and GenStage Available on Hex.pm: ecto_job | Hex Docs: API Reference — ec...
New
New

Other popular topics Top

9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
New
Jim
As a follow up to my earlier question: I have the code compiling and running but not getting a successful login from the rest server. ...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> someth...
New

Sub Categories:

We're in Beta

About us Mission Statement