{
  "category": "Our 10 featured functions",
  "display_name": "XLOOKUP",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.XLOOKUP",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 75 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 75 recorded answers",
    "workbook_corpus": {
      "cells": 75,
      "matched": 75
    }
  },
  "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#L142-L155",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/lookup.rs#L1235-L1249",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/lookup.rs#L1251-L1309",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/lookup.rs#L1311-L1362"
      ],
      "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::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#L142-L155",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 75 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.XLOOKUP.json",
  "name": "XLOOKUP",
  "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- **`XLOOKUP` supersedes `VLOOKUP`, `HLOOKUP` and `LOOKUP`.** It covers all three, in both\n  orientations, with an exact-match default, an explicit not-found value, backward search, and\n  a return array that need not lie to the right of (or below) the search vector. Microsoft has\n  not deprecated the older functions: they remain supported, and existing workbooks keep\n  working. For new work `XLOOKUP` is the better default.\n- **`XMATCH`** is `XLOOKUP` without the return step: same `match_mode` and `search_mode`\n  vocabulary, returning the position instead of the value. `INDEX(R, XMATCH(v, L, ...))` is\n  `XLOOKUP` decomposed.\n- **`FILTER`** answers a different question: all rows satisfying a predicate, not the one row\n  matching a key.\n- Readers coming from `INDEX`/`MATCH` should note that `XLOOKUP`'s alignment is positional\n  along the matching axis, exactly as `INDEX`/`MATCH`'s is — the relationship is a repackaging,\n  not a new mechanism.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n\n- The four `match_mode` values are not four settings of one comparison; wildcard mode changes\n  the predicate from equality to pattern matching, and the two \"next item\" modes require an\n  order over values that exact mode does not need.\n- `search_mode` and `match_mode` interact. Binary search is only coherent with an ordered\n  predicate; what binary search does under wildcard mode is a real question, not a\n  don't-care.\n- Blank-skipping belongs to the ordered search paths. An implementation that treats a blank\n  as an incomparable value and aborts will fail on ordinary trailing-blank ranges.\n- `lookup_value` must admit arrays, and `return_array` must be able to yield a whole row or\n  column per match. Those two together mean the natural result shape is not always a vector.\n- `if_not_found` is returned verbatim; it is not coerced to the return array's type, and it\n  can itself be an array.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\n`XLOOKUP` returns whatever `return_array` holds at the matched position: a scalar for a vector\nreturn array, or an entire row or column for a two-dimensional one. The row-or-column return\nis what makes `XLOOKUP` usable as a record fetch — one call, whole record — where `VLOOKUP`\nneeds one call per field.\n\n- **Binary search modes on unsorted data.** Microsoft states only that binary search \"relies\n  on\" the array being sorted. As with `VLOOKUP`'s approximate mode, that is a precondition\n  rather than a checked constraint: unsorted input under `search_mode` `±2` yields a\n  deterministic but undocumented answer, not an error.\n- Empty cells, omitted arguments, and error inputs follow the shared rules in\n  [coercion and lifting](../model/02-coercion-and-lifting.md); the reference-aware argument\n  preparation `XLOOKUP` carries is described in\n  [the call pipeline](../model/03-call-pipeline.md).\n\n\n\n### Errors\n\n\nDocumented by Microsoft: `#N/A` when no match exists and no `if_not_found` was supplied.\nMicrosoft additionally warns that binary search modes over an unsorted array produce invalid\nresults — note that this is a warning about *wrong answers*, not about an error value.\n\n`XLOOKUP` is also commonly reported to return `#VALUE!` when `lookup_array` and `return_array`\nhave incompatible dimensions, and `#REF!` for arrays in different workbooks in some\nconfigurations. The Handbook has not verified either against the current documentation page or\nagainst a live build, and does not assert them.\n\n\n",
    "sources": "- Microsoft, *XLOOKUP function* —\n  <https://support.microsoft.com/en-us/office/xlookup-function-b7fd680e-6d10-43e6-84f9-88eae8bf5929>\n  (syntax, argument table, the full `match_mode` and `search_mode` value tables and their\n  defaults, and the `#N/A` and unsorted-binary-search notes). Retrieved for this page.\n- Handbook `content/model/02-coercion-and-lifting.md` and `content/model/03-call-pipeline.md`.\n- Handbook `data/functions/FUNC.XLOOKUP.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`XLOOKUP` finds a position in one vector and returns the corresponding slice of another.\nGiven a lookup value `v`, a lookup array `L` of `n` entries, and a return array `R`, it\ndetermines an index `i ∈ 1..n` by the match rule below and returns `R`'s `i`-th slice — a\nsingle value when `R` is a vector, and a whole row or column when `R` is a two-dimensional\narea aligned to `L`.\n\nThe separation is the design point. In `VLOOKUP` the returned column is named by a positional\ninteger counted inside the searched table, so the search and the return are coupled through a\nshared geometry. In `XLOOKUP` they are two independent arguments: `R` may sit to the left of\n`L`, may be wider or taller, and may live in a different part of the sheet, as long as its\nlength along the matching axis equals `L`'s.\n\nThe match rule is a two-dimensional choice, and both dimensions are explicit:\n\n- **`match_mode`** decides *what counts as a match*: exact only (default), exact-or-next-\n  smaller, exact-or-next-larger, or wildcard.\n- **`search_mode`** decides *how the vector is traversed*: forward from the first item,\n  backward from the last, or by binary search assuming `L` is sorted ascending or descending.\n\nMaking both explicit is the substantive improvement over the older lookups, where the two\nwere entangled in one flag and the default silently chose the risky combination. `XLOOKUP`'s\ndefault is exact match, forward search — the combination whose failure mode is a visible\n`#N/A` rather than a plausible wrong number.\n\n\n\n### Arguments\n\n\nMicrosoft documents the signature as\n`XLOOKUP(lookup_value, lookup_array, return_array, [if_not_found], [match_mode], [search_mode])`.\n\n**`lookup_array`** — the array or range to search. Its length along the matching axis fixes\nthe correspondence with `return_array`.\n\n**`return_array`** — the array or range to return from. Aligned to `lookup_array` by position,\nnot by address.\n\n**`if_not_found`** — optional. The value to return when no match is found. When it is absent,\na miss is `#N/A`. This argument is the reason `IFNA(XLOOKUP(...), ...)` is usually redundant.\n\n**`match_mode`** — optional, default `0`:\n\n| Value | Documented meaning |\n|---|---|\n| `0` | Exact match; if none found, return `#N/A` (default) |\n| `-1` | Exact match; if none found, return the next smaller item |\n| `1` | Exact match; if none found, return the next larger 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 starting at the first item (default) |\n| `-1` | Reverse search starting at the last item |\n| `2` | Binary search; relies on `lookup_array` being sorted ascending |\n| `-2` | Binary search; relies on `lookup_array` being sorted descending |\n\nThe two argument positions most commonly misread are `match_mode` and `search_mode`\nthemselves — they are easy to swap, and both accept small signed integers, so a swap is not a\ntype error. `XLOOKUP(v, L, R, , -1)` is \"next smaller item, forward search\"; `XLOOKUP(v, L, R,\n, , -1)` is \"exact match, searched backwards\". They are different functions, and both are\nspelled with a `-1`.\n\nNote also the fourth position: `if_not_found` sits *between* the return array and the mode\nflags. Writing `XLOOKUP(v, L, R, 0)` intending exact match sets the not-found value to `0` and\nleaves the mode at its default — a mistake that produces `0` instead of `#N/A` on a miss.\n\n\n"
  },
  "signature": {
    "display": "XLOOKUP(lookup_value, lookup_array, return_array, [if_not_found], [match_mode], [search_mode])",
    "parameters": [
      {
        "description": "Current mixed tranche carries the modern lookup-value entry point.",
        "name": "lookup_value",
        "optional": false,
        "repeats": false
      },
      {
        "description": "Lookup vector used for match search.",
        "name": "lookup_array",
        "optional": false,
        "repeats": false
      },
      {
        "description": "Return vector or area paired to the lookup array.",
        "name": "return_array",
        "optional": false,
        "repeats": false
      },
      {
        "description": "Optional not-found projection lane.",
        "name": "if_not_found",
        "optional": true,
        "repeats": false
      },
      {
        "description": "Controls exact, approximate, and wildcard matching.",
        "name": "match_mode",
        "optional": true,
        "repeats": false
      },
      {
        "description": "Controls forward, reverse, and binary-style search direction.",
        "name": "search_mode",
        "optional": true,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 6,
        "min": 3
      },
      "category": "Our 10 featured functions",
      "classification": {
        "arg_preparation_profile": "RefsVisibleInAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "None",
        "fec_dependency_profile": "RefOnly",
        "host_interaction_class": "WorkbookState",
        "kernel_signature_class": "LookupMatch",
        "rich_value_usage": "RichBlind",
        "surface_fec_dependency_profile": "RefOnly",
        "thread_safety_class": "SafePure",
        "volatility_class": "NonVolatile"
      },
      "descriptions": {
        "long": "The first widened tranche uses XLOOKUP as the modern lookup representative beyond the bounded HVLOOKUP family seed.",
        "short": "The item matching a search in one array, taken from another, with a fallback and match options",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Use this function when you need to search a range or an array, and return an item corresponding to the first match it finds. If a match doesn't exist, then XLOOKUP can return the closest (approximate) match.",
        "microsoft_url": "https://support.microsoft.com/en-us/office/xlookup-function-b7fd680e-6d10-43e6-84f9-88eae8bf5929"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "XLOOKUP"
        },
        {
          "locale": "bg-BG",
          "name": "XLOOKUP"
        },
        {
          "locale": "cs-CZ",
          "name": "XLOOKUP"
        },
        {
          "locale": "da-DK",
          "name": "XOPSLAG"
        },
        {
          "locale": "de-DE",
          "name": "XLOOKUP"
        },
        {
          "locale": "el-GR",
          "name": "XLOOKUP"
        },
        {
          "locale": "en-AU",
          "name": "XLOOKUP"
        },
        {
          "locale": "en-GB",
          "name": "XLOOKUP"
        },
        {
          "locale": "en-US",
          "name": "XLOOKUP"
        },
        {
          "locale": "es-ES",
          "name": "BUSCARX"
        },
        {
          "locale": "et-EE",
          "name": "XLOOKUP"
        },
        {
          "locale": "fi-FI",
          "name": "XHAKU"
        },
        {
          "locale": "fr-FR",
          "name": "RECHERCHEX*"
        },
        {
          "locale": "he-IL",
          "name": "XLOOKUP"
        },
        {
          "locale": "hr-HR",
          "name": "XLOOKUP"
        },
        {
          "locale": "hu-HU",
          "name": "XKERES"
        },
        {
          "locale": "id-ID",
          "name": "XLOOKUP"
        },
        {
          "locale": "it-IT",
          "name": "XLOOKUP"
        },
        {
          "locale": "ja-JP",
          "name": "XLOOKUP"
        },
        {
          "locale": "ko-KR",
          "name": "XLOOKUP"
        },
        {
          "locale": "lt-LT",
          "name": "XLOOKUP"
        },
        {
          "locale": "lv-LV",
          "name": "XLOOKUP"
        },
        {
          "locale": "nb-NO",
          "name": "XLOOKUP"
        },
        {
          "locale": "nl-NL",
          "name": "X.ZOEKEN"
        },
        {
          "locale": "pl-PL",
          "name": "X.WYSZUKAJ"
        },
        {
          "locale": "pt-BR",
          "name": "XLOOKUP"
        },
        {
          "locale": "pt-PT",
          "name": "PROCX"
        },
        {
          "locale": "ro-RO",
          "name": "XLOOKUP"
        },
        {
          "locale": "ru-RU",
          "name": "ПРОСМОТРX"
        },
        {
          "locale": "sk-SK",
          "name": "XLOOKUP"
        },
        {
          "locale": "sl-SI",
          "name": "XLOOKUP"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "XLOOKUP"
        },
        {
          "locale": "sv-SE",
          "name": "XLETAUPP"
        },
        {
          "locale": "th-TH",
          "name": "XLOOKUP"
        },
        {
          "locale": "tr-TR",
          "name": "ÇAPRAZARA"
        },
        {
          "locale": "uk-UA",
          "name": "XLOOKUP"
        },
        {
          "locale": "vi-VN",
          "name": "XLOOKUP"
        },
        {
          "locale": "zh-CN",
          "name": "XLOOKUP"
        },
        {
          "locale": "zh-HK",
          "name": "XLOOKUP"
        },
        {
          "locale": "zh-TW",
          "name": "XLOOKUP"
        }
      ],
      "signature": {
        "display": "XLOOKUP(lookup_value, lookup_array, return_array, [if_not_found], [match_mode], [search_mode])",
        "parameters": [
          {
            "description": "Current mixed tranche carries the modern lookup-value entry point.",
            "name": "lookup_value",
            "optional": false,
            "repeats": false
          },
          {
            "description": "Lookup vector used for match search.",
            "name": "lookup_array",
            "optional": false,
            "repeats": false
          },
          {
            "description": "Return vector or area paired to the lookup array.",
            "name": "return_array",
            "optional": false,
            "repeats": false
          },
          {
            "description": "Optional not-found projection lane.",
            "name": "if_not_found",
            "optional": true,
            "repeats": false
          },
          {
            "description": "Controls exact, approximate, and wildcard matching.",
            "name": "match_mode",
            "optional": true,
            "repeats": false
          },
          {
            "description": "Controls forward, reverse, and binary-style search direction.",
            "name": "search_mode",
            "optional": true,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "XLOOKUP",
      "version_marker": null,
      "xlcall": null
    },
    "microsoft": "https://support.microsoft.com/en-us/office/xlookup-function-b7fd680e-6d10-43e6-84f9-88eae8bf5929"
  },
  "try_it": {
    "formula": "=XLOOKUP(2,{1;2;3},{\"one\";\"two\";\"three\"})"
  },
  "url": "https://handbook.dnacalc.com/functions/XLOOKUP.html",
  "variants": [],
  "versions": []
}