{
  "category": "Lookup and reference functions",
  "display_name": "XMATCH",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.XMATCH",
  "implementation_state": {
    "answer_bank": {
      "excel_builds": [
        "20527"
      ],
      "larger_numeric": 0,
      "last_bit": 0,
      "matched": 13,
      "other_mismatch": 0,
      "refused": 0,
      "rows": 13,
      "unread": 0,
      "worst_ulp": 0
    },
    "detail": "Recorded: 13 in the answer bank and 238 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 251 recorded answers",
    "workbook_corpus": {
      "cells": 238,
      "matched": 238
    }
  },
  "implementations": [
    {
      "commit": "9e1884369a678158dd82d3d74188daf986995e87",
      "flavour": "excel-compatibility-candidate",
      "language": "Rust",
      "name": "CalcFunc",
      "own_code": [
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/lookup.rs#L130-L141",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/lookup.rs#L1193-L1203",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/lookup.rs#L1205-L1230"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/comparison::texts",
        "catalogue/comparison/collation::compare",
        "catalogue/comparison/collation::weighed",
        "catalogue/comparison/collation::measured_iteration_extension",
        "catalogue/comparison/sort_key::table",
        "catalogue/comparison/sort_key::decode64",
        "catalogue/comparison/sort_key::Reader::byte",
        "catalogue/comparison/sort_key::Reader::varint",
        "catalogue/comparison/sort_key::Reader::done",
        "catalogue/comparison/sort_key::in_ranges",
        "catalogue/comparison/sort_key::build",
        "catalogue/comparison/sort_key::han_base",
        "catalogue/comparison/sort_key::derive",
        "catalogue/comparison/sort_key::shared_jamo_tails",
        "catalogue/comparison/sort_key::ordinary_jamo_prefix",
        "catalogue/comparison/sort_key::independent_jamo_suffix",
        "catalogue/comparison/sort_key::jamo_leading_primary",
        "catalogue/comparison/sort_key::leading_order",
        "catalogue/comparison/sort_key::Before::separate_special",
        "catalogue/comparison/sort_key::Gathered::kana",
        "catalogue/comparison/sort_key::Gathered::unit",
        "catalogue/comparison/sort_key::parts",
        "catalogue/comparison/sort_key::diacritic_order",
        "catalogue/comparison/sort_key::diacritics",
        "catalogue/lookup::eager",
        "catalogue/lookup::Item::rank",
        "catalogue/lookup::item",
        "catalogue/lookup::lookup_key",
        "catalogue/lookup::equal",
        "catalogue/lookup::error_rank",
        "catalogue/lookup::order",
        "catalogue/lookup::pattern",
        "catalogue/lookup::matches",
        "catalogue/lookup::hits",
        "catalogue/lookup::Line::len",
        "catalogue/lookup::Line::scan",
        "catalogue/lookup::Line::held",
        "catalogue/lookup::Held::blank",
        "catalogue/lookup::reader",
        "catalogue/lookup::cell_value",
        "catalogue/lookup::rows",
        "catalogue/lookup::columns",
        "catalogue/lookup::row_line",
        "catalogue/lookup::column_line",
        "catalogue/lookup::line",
        "catalogue/lookup::value",
        "catalogue/lookup::span",
        "catalogue/lookup::shape",
        "catalogue/lookup::first_hit",
        "catalogue/lookup::xmatch_linear",
        "catalogue/lookup::xmatch_binary",
        "catalogue/lookup::index_number",
        "catalogue/lookup::modes",
        "catalogue/lookup::xsearch",
        "catalogue/lookup::position",
        "catalogue/lookup::index",
        "catalogue/lookup::selector",
        "catalogue/lookup::indexed",
        "catalogue/lookup::select",
        "catalogue/lookup::row",
        "catalogue/lookup::column",
        "catalogue/lookup::position_of",
        "catalogue/lookup::areas"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/lookup.rs#L130-L141",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 251 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.XMATCH.json",
  "name": "XMATCH",
  "notes": [],
  "schema": "efh.function-reference/v1",
  "section_order": [
    "what-it-does",
    "try-it",
    "quirks",
    "how-to-implement",
    "version-differences",
    "alternatives"
  ],
  "sections": {
    "alternatives": "\n### Relationships\n\n\n- **`XMATCH` supersedes `MATCH`.** Same job, orthogonal controls, exact-match default, plus\n  reverse and binary search. Microsoft has not deprecated `MATCH`, which remains supported.\n- **`XLOOKUP`** is `XMATCH` plus the return step, sharing the `match_mode` and `search_mode`\n  vocabulary exactly. `INDEX(R, XMATCH(v, L, m, s))` and `XLOOKUP(v, L, R, , m, s)` are the\n  same query written two ways; the difference is that `XLOOKUP` also carries `if_not_found`.\n- **`INDEX`** is the usual consumer of `XMATCH`'s result.\n- **`VLOOKUP`/`HLOOKUP`** contain a `MATCH`-shaped search internally; `XMATCH` is the modern\n  standalone form of that search.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n- `match_mode` and `search_mode` are independent inputs to one search, and the implementation\n  has to decide what each of the sixteen combinations means. Wildcard matching under binary\n  search is the combination with no documented meaning; it should be a recorded decision, not\n  an accident of code structure.\n- Reverse exact search must return the *last* matching index, which means it cannot be\n  implemented as forward search over a reversed array without mapping the index back.\n- The same index-mapping obligation applies to blank skipping under binary search: the search\n  runs over the comparable subsequence, and the chosen position must be translated back to the\n  original 1-based index. `BUG-FUNC-040` records exactly this repair.\n- Exact mode is numerically strict while much of Excel's comparison surface is tolerant; the\n  two comparison helpers must not be shared.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nThe return kind is a number: an index relative to `lookup_array`, not to the worksheet.\n\n- **Exact numeric comparison is strict.** `BUG-FUNC-004`, signed off against live Excel 16.0\n  build 20026 on 2026-06-20, records `=XMATCH(0.1+0.2,{0.3},0)` → `#N/A`, deliberately\n  contrasted with the tolerant comparison families where `=0.1+0.2=0.3` is `TRUE`.\n- **Binary search on unsorted input** returns something rather than erroring. Microsoft states\n  only that results are invalid; the behaviour is therefore undefined by documentation, not\n  defined-and-bad.\n- Errors, blanks and omitted arguments otherwise follow\n  [coercion and lifting](../model/02-coercion-and-lifting.md).\n\n\n\n### Errors\n\n\nDocumented: no error is named beyond the ordinary `#N/A` for a value not found, and a warning\nthat binary search over an unsorted array yields invalid results — wrong answers, not an error\nvalue.\n\nError values arriving in `lookup_value` propagate. What an error *inside* `lookup_array` does\nis not documented; `BUG-FUNC-040` names the error-cell lane as an explicitly separate, open\nprobe, which is a fair signal that nobody has pinned it.\n\n\n",
    "sources": "- Microsoft, *XMATCH function* —\n  <https://support.microsoft.com/en-us/office/xmatch-function-d966da31-7a6b-4a13-a1c6-5a33ed6a0312>\n  (syntax, the `match_mode` and `search_mode` value tables and defaults, and the\n  unsorted-binary-search warning). Retrieved for this page.\n- Microsoft, *MATCH function* —\n  <https://support.microsoft.com/en-us/office/match-function-e8dffd45-c762-47d6-bf89-533f4a37673a>\n  (the superseded function and its documented cross-type sort order).\n- Handbook `content/model/02-coercion-and-lifting.md` and `content/model/03-call-pipeline.md`.\n- Handbook `data/functions/FUNC.XMATCH.json` (signature, arity, classification axes).\n\n",
    "version-differences": "No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.",
    "what-it-does": "\n`XMATCH` returns the 1-based position of a value within a range or array. Given a lookup value\n`v` and a lookup array `L` of `n` entries, it selects an index `i ∈ 1..n` and returns `i`, or\n`#N/A`.\n\nWhat distinguishes it from `MATCH` is that the single ternary `match_type` flag is split into\ntwo orthogonal arguments:\n\n- **`match_mode`** — the predicate. Exact (default), exact-or-next-smallest,\n  exact-or-next-largest, or wildcard.\n- **`search_mode`** — the traversal. First-to-last (default), last-to-first, binary ascending,\n  or binary descending.\n\nThat split is not cosmetic. In `MATCH`, choosing \"nearest below\" also chose \"assume ascending\nsort\" and (in practice) a particular traversal; the three were welded together. In `XMATCH`\nyou can ask for an exact match searched backwards — which is how you find the *last*\noccurrence of a repeated key, something `MATCH` cannot express at all. You can also ask for a\nnearest-below match over a linearly scanned array, without committing to the sorted-array\npremise that binary search requires.\n\nThe default combination is exact match, first-to-last. Its failure mode is `#N/A`: visible.\nThat is a deliberate reversal of `MATCH`'s default, whose failure mode is a plausible wrong\nindex.\n\n\n\n### Arguments\n\n\nMicrosoft documents `XMATCH(lookup_value, lookup_array, [match_mode], [search_mode])`.\n\n**`lookup_value`** — the value to locate.\n\n**`lookup_array`** — the array or range to search.\n\n**`match_mode`** — optional, default `0`:\n\n| Value | Documented meaning |\n|---|---|\n| `0` | Exact match (default) |\n| `-1` | Exact match or next smallest item |\n| `1` | Exact match or next largest item |\n| `2` | A wildcard match where `*`, `?` and `~` have special meaning |\n\n**`search_mode`** — optional, default `1`:\n\n| Value | Documented meaning |\n|---|---|\n| `1` | Search first-to-last (default) |\n| `-1` | Search last-to-first |\n| `2` | Binary search, `lookup_array` sorted ascending |\n| `-2` | Binary search, `lookup_array` sorted descending |\n\nThe position most often misused is the third. `XMATCH(v, L, -1)` is *not* a reverse search — it\nis \"exact or next smallest, searched forwards\". A reverse search is `XMATCH(v, L, 0, -1)`.\nBoth spellings contain a `-1` and neither is a type error, so the mistake survives entry and\nshows up as a subtly wrong index.\n\nNote also that `match_mode` `±1` does **not** by itself require a sorted array — only\n`search_mode` `±2` does. Nearest-below over an unsorted array is a legal, meaningful request\nunder linear traversal. This is a genuine expressive gain over `MATCH` and is easy to overlook.\n\n\n"
  },
  "signature": {
    "display": "XMATCH(lookup_value, lookup_array, [match_mode], [search_mode])",
    "parameters": [
      {
        "description": null,
        "name": "lookup_value",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "lookup_array",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "match_mode",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "search_mode",
        "optional": true,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 4,
        "min": 2
      },
      "category": "Lookup and reference functions",
      "classification": {
        "arg_preparation_profile": "ValuesOnlyPreAdapter",
        "coercion_lift_profile": "LookupMatchProfile",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "None",
        "fec_dependency_profile": "None",
        "host_interaction_class": "None",
        "kernel_signature_class": "LookupMatch",
        "rich_value_usage": "RichBlind",
        "surface_fec_dependency_profile": "RefOnly",
        "thread_safety_class": "SafePure",
        "volatility_class": "NonVolatile"
      },
      "descriptions": {
        "long": null,
        "short": "Position of a value in an array, with match and search options",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Returns the relative position of an item in an array or range of cells.",
        "microsoft_url": "https://support.microsoft.com/en-us/office/xmatch-function-d966da31-7a6b-4a13-a1c6-5a33ed6a0312"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "XMATCH"
        },
        {
          "locale": "bg-BG",
          "name": "XMATCH"
        },
        {
          "locale": "cs-CZ",
          "name": "XMATCH"
        },
        {
          "locale": "da-DK",
          "name": "XSAMMENLIGN"
        },
        {
          "locale": "de-DE",
          "name": "XMATCH"
        },
        {
          "locale": "el-GR",
          "name": "XMATCH"
        },
        {
          "locale": "en-AU",
          "name": "XMATCH"
        },
        {
          "locale": "en-GB",
          "name": "XMATCH"
        },
        {
          "locale": "en-US",
          "name": "XMATCH"
        },
        {
          "locale": "es-ES",
          "name": "COINCIDIRX"
        },
        {
          "locale": "et-EE",
          "name": "XMATCH"
        },
        {
          "locale": "fi-FI",
          "name": "XVASTINE"
        },
        {
          "locale": "fr-FR",
          "name": "EQUIVX*"
        },
        {
          "locale": "he-IL",
          "name": "XMATCH"
        },
        {
          "locale": "hr-HR",
          "name": "XMATCH"
        },
        {
          "locale": "hu-HU",
          "name": "XHOL.VAN"
        },
        {
          "locale": "id-ID",
          "name": "XMATCH"
        },
        {
          "locale": "it-IT",
          "name": "XMATCH"
        },
        {
          "locale": "ja-JP",
          "name": "XMATCH"
        },
        {
          "locale": "ko-KR",
          "name": "XMATCH"
        },
        {
          "locale": "lt-LT",
          "name": "XMATCH"
        },
        {
          "locale": "lv-LV",
          "name": "XMATCH"
        },
        {
          "locale": "nb-NO",
          "name": "XMATCH"
        },
        {
          "locale": "nl-NL",
          "name": "X.VERGELIJKEN"
        },
        {
          "locale": "pl-PL",
          "name": "X.DOPASUJ"
        },
        {
          "locale": "pt-BR",
          "name": "XMATCH"
        },
        {
          "locale": "pt-PT",
          "name": "CORRESPX"
        },
        {
          "locale": "ro-RO",
          "name": "XMATCH"
        },
        {
          "locale": "ru-RU",
          "name": "ПОИСКПОЗX"
        },
        {
          "locale": "sk-SK",
          "name": "XMATCH"
        },
        {
          "locale": "sl-SI",
          "name": "XMATCH"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "XMATCH"
        },
        {
          "locale": "sv-SE",
          "name": "XMATCHNING"
        },
        {
          "locale": "th-TH",
          "name": "XMATCH"
        },
        {
          "locale": "tr-TR",
          "name": "ÇAPRAZEŞLEŞTİR"
        },
        {
          "locale": "uk-UA",
          "name": "XMATCH"
        },
        {
          "locale": "vi-VN",
          "name": "XMATCH"
        },
        {
          "locale": "zh-CN",
          "name": "XMATCH"
        },
        {
          "locale": "zh-HK",
          "name": "XMATCH"
        },
        {
          "locale": "zh-TW",
          "name": "XMATCH"
        }
      ],
      "signature": {
        "display": "XMATCH(lookup_value, lookup_array, [match_mode], [search_mode])",
        "parameters": [
          {
            "description": null,
            "name": "lookup_value",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "lookup_array",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "match_mode",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "search_mode",
            "optional": true,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "XMATCH",
      "version_marker": null,
      "xlcall": null
    },
    "microsoft": "https://support.microsoft.com/en-us/office/xmatch-function-d966da31-7a6b-4a13-a1c6-5a33ed6a0312"
  },
  "try_it": {
    "formula": "=XMATCH(2,{1;2;3},0)"
  },
  "url": "https://handbook.dnacalc.com/functions/XMATCH.html",
  "variants": [],
  "versions": []
}