Dev tool

Compare Two Lists

This list compare tool takes two blocks of text and returns all five set relationships between them at once: the items common to both, the items only in the first list, the items only in the second, everything that appears in exactly one list, and every distinct item across both. Paste, drop a file, or send a result back into an input box to chain comparisons.

Nothing is uploaded. Splitting, normalization and the set arithmetic all run in your browser, and every list shows its own accounting line — 1,842 lines → 1,790 unique — so no row ever disappears without an explanation.

0 characters pasted

0 characters pasted

Matching rules

Result

Set relationships between your lists

Paste a list into each box to compare them.

List A: 0 characters pasted

List B: 0 characters pasted

Common to both

A ∩ B

0

Every item that appears in List A and in List B.

Nothing compared yet — paste a list into each box.

Only in List A

A \ B

0

In List A, missing from List B.

Nothing compared yet — paste a list into each box.

Only in List B

B \ A

0

In List B, missing from List A.

Nothing compared yet — paste a list into each box.

In exactly one list

A △ B

0

Everything the two lists do not share, from either side.

Nothing compared yet — paste a list into each box.

All unique items

A ∪ B

0

Every distinct item across both lists, counted once.

Nothing compared yet — paste a list into each box.

Occurrence counts

Set operations answer which items; this table answers how many times. Useful when a duplicate is the bug you are hunting.

No items yet.

Method

How comparing two lists works

Comparing two lists means computing four set relationships between them: the intersection (items in both), the two differences (items only in the first, items only in the second), and the symmetric difference (items in exactly one). A set, in the NIST definition, is "an unordered collection of values where each value occurs at most once" — which is why duplicates inside a single list collapse before any comparison happens, and why this tool prints how many collapsed instead of letting rows vanish.

The five-stage pipeline

  1. Split. Text is cut on CRLF, lone CR and LF, plus whichever separator you pick. Windows-pasted lists carry a carriage return that would otherwise ride along inside every item.
  2. Normalize. In order: invisible-character cleanup, trim, optional whitespace collapse, Unicode NFC, case fold, blank removal, optional leading-zero strip.
  3. Key versus display. Normalization produces a comparison key; the first-seen original text is kept for display. You never see the folded key in a result panel.
  4. Operate. Membership is a hash lookup, so each item is tested once against the other list's index.
  5. Report. Lines parsed, unique items and duplicates collapsed per list, plus the cardinality of every panel.

Set notation used in the panels

  • A ∩ B — intersection, what both lists contain.
  • A \ B — difference, in A but not in B.
  • B \ A — difference the other way round.
  • A △ B — symmetric difference, everything in exactly one list, which equals the union minus the intersection.
  • A ∪ B — union, every distinct item across both lists.

A worked example you can reproduce

Put apple, banana, cherry, Banana in List A and banana, cherry, date in List B, with trim and case-insensitive matching on. List A reports 4 lines → 3 unique because Banana folded onto banana. The panels then read: A ∩ B = banana, cherry (2); A \ B = apple (1); B \ A = date (1); A △ B = apple, date (2); A ∪ B = apple, banana, cherry, date (4). Switch case-insensitive matching off and four numbers move at once: List A becomes 4 lines → 4 unique, A \ B grows to apple and Banana (2), A △ B becomes 3 and A ∪ B becomes 5. The intersection holds at 2, because banana and cherry already matched exactly. Press Load example above to run it.

Why it stays fast on huge lists

Set membership is a hash lookup, so comparing two lists runs in O(n + m) time rather than the O(n × m) of the nested-loop scan a spreadsheet formula performs. Measured on this implementation, two 100,000-line lists compare in roughly 0.15 seconds and two 500,000-line lists — about 17 MB of text — in around one second. What actually breaks a browser is rendering, not arithmetic: a million table rows will freeze a tab long before the set operations break a sweat. That is why each panel renders its first 1,000 rows and hands you the rest as a download, and why anything past 50,000 parsed items is computed in a Web Worker so the page keeps responding while it runs. The native Set methods that express these operations directly reached Baseline on 11 June 2024; this tool builds its results from an ordered index instead, because the native intersection returns items in the order of the smaller list and would silently reorder your output.

Worked examples

Five real list comparison scenarios

1. Marketing ops applying a suppression list

List A holds 1,842 campaign contacts exported from the CRM; List B holds 306 suppressed addresses — unsubscribes, hard bounces, complaints. With trim, case-insensitive matching and blank removal on, List A reports 1,842 lines → 1,790 unique, 52 duplicates collapsed. Common to both = 214, only in A = 1,576, only in B = 92.

The "Only in List A" panel is the file you actually send. The 214 overlap is the count of messages you just avoided sending to people who opted out.

2. Reconciling a supplier feed against a storefront

4,310 supplier SKUs in the shape 00-4471-B against 4,188 live storefront SKUs, with case-sensitive matching on because SKU case is meaningful and leading-zero stripping off. Common = 4,102, only in A = 208, only in B = 86.

"Only in List B" is the urgent panel: 86 orderable products with no supply behind them. Turning leading-zero stripping on would collapse 00447 and 447 into one match and move both counts, so leave it off unless the two systems genuinely disagree about padding.

3. Auditing declared versus installed dependencies

187 package names declared in package.json against 203 resolved in node_modules, matched case-sensitively with JSON array output. Only in B = 19 — transitive packages pulled in but never declared, the phantom-dependency risk. Only in A = 3 — declared but unresolved, which is a broken install.

The verdict line reads "the lists overlap": neither is a subset of the other. Pipe the JSON array straight into a script, or clean it up first with the JSON formatter.

4. Checking a class roster against submissions

32 enrolled student names in List A, 29 submitters in List B, with trim, case-insensitive matching and Unicode normalization on because the names contain é, ñ and ü typed on different keyboards. Common = 28, only in A = 4 (non-submitters), only in B = 1 — a student who submitted but is not on the roster, i.e. a drop/add mismatch.

Switch Unicode normalization off and a name typed in decomposed form appears as a second false mismatch. This scenario is the concrete argument for leaving it on whenever human names are involved.

5. The four-item reference run

List A = apple, banana, cherry, Banana; List B = banana, cherry, date. A ∩ B = 2, A \ B = 1, B \ A = 1, A △ B = 2, A ∪ B = 4, and List A reports 4 lines → 3 unique. Small enough to verify by eye, which makes it the right test when you are unsure whether an option is doing what you think.

Standards

Unicode, case folding and the comparison key

List comparison is jurisdiction-agnostic — set arithmetic is the same in every country — but text equality is not obvious, and two standards govern it. Unicode Standard Annex #15 defines the normalization forms NFC, NFD, NFKC and NFKD, and states that canonically equivalent sequences must be normalized before they can be compared. The word café is one code point on Windows (U+00E9) and two on macOS filesystems (U+0065 U+0301); rendered they are identical, compared raw they are different. This tool applies NFC by default and lets you switch it off when you need byte fidelity for identifiers.

Case handling comes from the Unicode Standard core specification, section 5.18, which absorbed the retired UTR #21 in Unicode 4.0. It distinguishes case mapping (for display) from case folding (for caseless matching) and documents the locale tailorings — in Turkish, capital I lowercases to dotless ı, not i. Case-insensitive matching here uses the locale-independent fold deliberately: applying your browser's locale would make the same two lists produce different answers on a Turkish machine than on a British one, which is not a property a reconciliation tool should have.

Troubleshooting

Common mistakes when comparing two lists

  • A carriage return you cannot see. A list pasted from a Windows file splits into "apple\r" if the tool only cuts on \n, and then matches nothing. Splitting on all three newline forms and trimming is the fix, and it is on by default here.
  • Duplicates disappearing without a word. Set semantics collapse repeats by definition, so 1,842 pasted lines can produce 1,790 results. Read the accounting line under each box; if you actually need the repeat counts, open the occurrence table.
  • Composed versus decomposed accents. NFC and NFD spellings of the same accented word render identically and compare unequal. Leave Unicode normalization on for anything containing human names, place names or non-English text.
  • Locale-dependent lowercasing. A naive toLocaleLowerCase() makes results depend on the reader's operating system: under Turkish rules KISA and kısa fold together while KISA and kisa do not.
  • Invisible characters from copy-paste. A byte order mark on line one of an uploaded file, non-breaking spaces from a copied web table, and zero-width spaces from rich-text sources each manufacture phantom unique items. The cleanup toggle removes them and reports the count.
  • Leading zeros destroyed by Excel. Microsoft documents that Excel strips leading zeros, rewrites long numbers as scientific notation such as 1.23E+15, and rounds anything past 15 significant digits to zero. Scientific-notation damage is unrecoverable — re-export the column as text. Padding differences alone are fixable with "Ignore leading zeros".
  • Result order you did not ask for. The native intersection returns items in the order of the smaller list, so a ten-item List B would dictate the ordering of results drawn from a ten-thousand-item List A. Every panel here walks its source list instead, so "input order" means exactly that.
  • Email case assumptions. The local part of an address may be case-sensitive by RFC, but every real provider treats John@Example.com and john@example.com as one mailbox. Case-sensitive matching on an email list silently doubles a suppression list.
  • Assuming the tab froze. With half a million items the set arithmetic takes about a second; painting the results is what would hang the page. Above 50,000 items the work moves to a Web Worker and panels cap their rendering, so a slow moment is progress, not a crash.
  • Mixed delimiters in one paste. Comma-separated text in List A against one-per-line text in List B produces a single long item on one side. The counts under each box expose it immediately, and the tool offers the separator it detected.

Related concepts

Concepts worth knowing before you trust the numbers

Set theory in one paragraph

Draw two overlapping circles. The overlap is the intersection, each crescent is one difference, the two crescents together are the symmetric difference, and the whole shaded figure is the union. Every number this tool reports is one region of that diagram.

Deduplicating a single list

A strict subset of the same pipeline: split, normalize, insert into a set, emit. Paste into List A alone and the "Only in List A" panel is your deduplicated list, with the accounting line telling you exactly how many repeats came out.

Line diff versus set compare

A set comparison ignores order and position and reports membership only; a text diff is order-sensitive and reports insertions, deletions and moves. If you need to know what changed between two versions of the same document, you want a diff, not a list compare.

The spreadsheet equivalents

In Excel or Google Sheets the same job is an XLOOKUP wrapped in IFERROR, the conditional-formatting "Duplicate Values" rule, or a dynamic-array UNIQUE over VSTACK. All three work; all three are one formula per direction, and all three inherit Excel's number coercion.

Feeding the result into something else

The JSON array format drops straight into a script or an API payload; the quoted, comma-separated format is exactly the shape a SQL IN (…) clause wants, which pairs well with the SQL formatter once the query gets long.

Comparison

This tool versus the spreadsheet methods

Excel behaviour per Microsoft's "Keeping leading zeros and large numbers" documentation; timings for this tool measured on the implementation described above.
MethodSetup100k rowsKeeps leading zerosAll five set results
This toolPaste and read~0.15 sYes, text is never coercedYes, at once
XLOOKUP + IFERROROne formula per directionSlow, recalculates on editOnly if imported as textNo, two differences only
Conditional formattingRule per rangeSluggish, highlights onlyOnly if imported as textNo, visual overlap only
UNIQUE + VSTACKDynamic-array formulaWorkable, spill-range limitsOnly if imported as textUnion and dedupe only

FAQ

List compare questions, answered

How do I find items that are in one list but not the other?

Paste each list into its own box. The "Only in List A" panel is the set difference A \ B and "Only in List B" is B \ A. Both directions are computed in the same pass, so one comparison answers the question from both sides, and each panel has its own copy and download button so you can take just the side you need.

What is the difference between intersection, union and symmetric difference?

Intersection (A n B) is what both lists contain. Union (A u B) is every distinct item across both. Symmetric difference (A triangle B) is everything that appears in exactly one list, which is the union minus the intersection. With A = apple, banana, cherry, Banana and B = banana, cherry, date the intersection is 2 items, the union is 4, and the symmetric difference is 2 (apple and date).

Does the tool remove duplicates inside a single list?

Yes. Comparison uses set semantics, where each value occurs at most once, so repeats inside one list collapse before the comparison runs. Nothing disappears silently: the readout under each box states how many collapsed, for example "1,842 lines to 1,790 unique, 52 duplicates collapsed". Pasting into List A alone therefore gives you a deduplicated list as a side effect.

How do I compare two lists without worrying about capitalization?

Leave "Case-insensitive matching" on, which is the default. Items are folded to lower case to build the comparison key, but every panel shows the original casing you pasted. The fold is locale-independent on purpose: using your operating system locale would apply the Turkish rule that maps I to dotless i, and identical input would then produce different results on different machines.

Why do two identical-looking items show up as different?

Almost always an invisible character. The usual suspects are a trailing carriage return from a Windows paste, a non-breaking space copied out of a rendered web table, a UTF-8 byte order mark on the first line of an uploaded file, and an accented letter stored decomposed (NFD) rather than composed (NFC). Keep trim, invisible-character cleanup and Unicode normalization on; the readout reports how many characters each cleanup touched.

Are my lists uploaded to a server?

No. Splitting, normalization and every set operation run in your browser, on the main thread for small lists and in a Web Worker for large ones. No list content is transmitted, logged or stored, and the only thing this page requests from the network is its own JavaScript. You can confirm it by opening your browser devtools Network tab and comparing two lists with it open.

How large a list can I compare?

The enforced ceiling is 20 million characters across both boxes, roughly 20 MB of text, and 20 MB per uploaded file. Past 50,000 parsed items the comparison moves into a Web Worker so the page keeps responding, and each panel renders its first 1,000 rows with the full result available through download. On this implementation two 100,000-line lists compare in roughly 0.15 seconds and two 500,000-line lists in about one second.

Can I upload a file instead of pasting?

Yes. Drop a .txt, .csv, .tsv, .log or .md file on either box or use the browse button. The file is read locally with the File API, a UTF-8 byte order mark is stripped automatically, and a CSV or TSV is parsed as RFC 4180 records so you can pick which column to compare instead of splitting a quoted field down the middle.

My list is comma-separated, not one item per line. Will it work?

Yes. Choose comma, semicolon, tab, pipe, any whitespace, or type a custom separator. Line breaks always separate items as well, so a comma-separated block spread over several lines parses correctly. If a delimiter looks wrong the tool suggests the one it detected, and the counts under each box show immediately whether the split did what you expected.

Why did my SKU or ZIP code lose its leading zeros?

That damage happens in the spreadsheet, not here. Microsoft documents that Excel removes leading zeros, converts large numbers to scientific notation such as 1.23E+15, and rounds anything past 15 significant digits down to zero. Re-export the column as text, or switch on "Ignore leading zeros" so 00123 and 123 are treated as the same item.

Can I compare more than two lists?

Compare two at a time and chain the result. Run A against B, press "Send to A" on the panel you care about, then paste list C into List B. Intersection and union are associative, so (A n B) n C equals A n B n C, and the same trick narrows a suppression list across any number of sources.

How is this different from a text diff tool?

A diff is order-sensitive: it walks two documents line by line and reports insertions, deletions and moves in sequence. A list compare ignores order and position entirely and reports membership only. If you need to see what changed between two versions of the same file, use a diff. If you need to know which items are shared, missing or extra, this is the right shape of answer.

Authoritative sources

More free calculators and tools you might find useful