JSON array set diff

Paste two JSON arrays and get their union, intersection, difference or symmetric difference — compared as JSON values, or matched on an id field like lodash differenceBy.

Try:
Result

About this tool

Two JSON arrays, four questions: what is in both, what is in either, what is in A but not B, and what is on exactly one side. This tool answers all four — union, intersection, difference (A − B) and symmetric difference — over arrays you paste in, and reports the counts alongside the result so you can sanity-check the answer at a glance.

Elements are compared as JSON values, not as text. Object key order never matters, and 1, 1.0 and 1e0 are the same number, so two exports that serialise differently still line up. When the records differ in ways you do not care about — a changed name, a fresh updated_at — set Match on field to id (or a dot-path like meta.sku) and elements are paired on that field only, the way lodash's differenceBy family works.

It suits the everyday list jobs: finding the user ids present in an export but missing from the database, deduplicating a merged tag list, checking which SKUs two feeds share, or diffing two API result sets by primary key. Input can be a JSON array or NDJSON (one JSON value per line), which is what most exports paste as. Everything runs locally in your browser through WebAssembly — neither array is uploaded anywhere.

Worked example

Array A

[{"id":1,"name":"Ada"},{"id":2,"name":"Bo"},{"id":3,"name":"Cy"}]

Array B

[{"id":2,"name":"CHANGED"}]

With Operation set to Difference (A − B) and Match on field set to id, the result is:

{
  "operation": "difference",
  "matched_by": "id",
  "counts": {
    "a": 3,
    "b": 1,
    "a_unique": 3,
    "b_unique": 1,
    "only_in_a": 2,
    "only_in_b": 0,
    "in_both": 1,
    "union": 3,
    "result": 2
  },
  "result": [
    {"id": 1, "name": "Ada"},
    {"id": 3, "name": "Cy"}
  ]
}

Ada and Cy are missing from B; Bo matched on id even though every other field changed. The counts block always describes the two sets (distinct match keys), so it stays meaningful whether or not repeats are collapsed in the result. Switch Output to Result array only to get the bare [{"id":1,…},{"id":3,…}] you can paste straight into the next step, and set Indent to 0 to minify it onto one line.

Limits and edge cases

FAQ

When are two elements "the same"?

By default, when their whole JSON values are equal after canonicalisation: object keys are sorted, so {"a":1,"b":2} and {"b":2,"a":1} match, and numbers are normalised, so 1 and 1.0 match. Whitespace and key order in your paste are irrelevant. If you set Match on field, only that field's value is compared and everything else is ignored.

How do I compare records that have changed fields, like lodash differenceBy?

Put the identifying field in Match on fieldid, email, sku. Nested fields use a dot-path: meta.sku, and array positions work too (tags.0). Elements are then paired on that value alone, so a record whose name or updated_at changed still counts as present on both sides.

Which array do the returned elements come from?

Array A, wherever the operation could draw from either side. Intersection returns A's version of each shared element, union returns all of A and then only the elements of B that A did not already have, and symmetric difference returns A-only elements first, then B-only ones. That means the fields you see are A's fields — useful when B is a trimmed id list.

Can I paste NDJSON or a log-style export?

Yes. If the text does not start with [, it is read as NDJSON: one JSON value per line, blank lines skipped, two or more lines required. Mixing the two formats between the boxes is fine — array A can be NDJSON while array B is a plain array.

Is my data uploaded anywhere?

No. The set logic is compiled to WebAssembly and runs inside your browser tab, so both arrays stay on your machine. Nothing is sent to a server, logged, or stored — you can load the page, disconnect, and it still works.

Developer & Automation Access

Run it from the terminal

Same engine as this page, headless — via the gizza CLI:

gizza tool set-diff-json '[{"id": 1, "name": "Ada"}, {"id": 2, "name": "Bo"}]' 'array_b=[{"id": 2, "name": "Bo"}, {"id": 3, "name": "Cy"}]'

New to the CLI? Get gizza →

Open it by URL

Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:

https://gizza.ai/tools/set-diff-json/?array_a=%5B%7B%22id%22%3A%201%2C%20%22name%22%3A%20%22Ada%22%7D%2C%20%7B%22id%22%3A%202%2C%20%22name%22%3A%20%22Bo%22%7D%5D&array_b=%5B%7B%22id%22%3A%202%2C%20%22name%22%3A%20%22Bo%22%7D%2C%20%7B%22id%22%3A%203%2C%20%22name%22%3A%20%22Cy%22%7D%5D&operation=difference&key=id&case_insensitive=true&dedupe=true&output=report&indent=2

Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.