{
  "category": "Lookup and reference functions",
  "display_name": "INDEX",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.INDEX",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Of 12,437 recorded answers (12,437 workbook cells), 264 do not match: 24 differ in kind or value, 240 are refused.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "differs",
    "state_label": "Known larger differences",
    "summary": "Known larger differences on 264 of 12,437 recorded answers",
    "workbook_corpus": {
      "cells": 12440,
      "matched": 12173,
      "other_mismatch": 24,
      "pending": 3,
      "refused": 240
    }
  },
  "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#L107-L118"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/lookup::eager",
        "catalogue/lookup::pattern",
        "catalogue/lookup::matches",
        "catalogue/lookup::Line::len",
        "catalogue/lookup::Line::scan",
        "catalogue/lookup::reader",
        "catalogue/lookup::cell_value",
        "catalogue/lookup::rows",
        "catalogue/lookup::columns",
        "catalogue/lookup::value",
        "catalogue/lookup::span",
        "catalogue/lookup::shape",
        "catalogue/lookup::index_number",
        "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#L107-L118",
      "state": "differs",
      "suite": null,
      "summary": "Known larger differences on 264 of 12,437 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.INDEX.json",
  "name": "INDEX",
  "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- **`MATCH`** is the other half of the `INDEX`/`MATCH` idiom: `MATCH` computes a position,\n  `INDEX` retrieves it. The pair replaces `VLOOKUP`/`HLOOKUP` and removes their two structural\n  limits — the key column need not be first, and the result index need not be counted by hand.\n- **`XLOOKUP`** subsumes the common `INDEX`/`MATCH` case in one call. `INDEX`/`MATCH` remains\n  the more flexible construction, particularly for two-dimensional lookups\n  (`INDEX(a, MATCH(...), MATCH(...))`) and for anything needing a reference result.\n- **`OFFSET`** also computes a reference and is volatile; `INDEX` is not. Where an `OFFSET`\n  formula can be rewritten with `INDEX`, it usually should be.\n- **`AREAS`** counts the areas that `area_num` selects among; `INDEX(ref, r, c, AREAS(ref))` is\n  the \"last area\" idiom.\n- **`CHOOSEROWS` / `CHOOSECOLS`** are the modern, array-returning way to do the zero-coordinate\n  trick for several rows or columns at once — but they return values, not references, so they\n  do not substitute for the reference form.\n- **`INDIRECT`** is the other route to a computed reference, via text. It is volatile and\n  invisible to the dependency graph; `INDEX` is neither. When both would work, `INDEX` is the\n  better-behaved choice.\n- **The range operator** (`FUNC.OP_RANGE_REF`, `:`) is `INDEX`'s most important collaborator in\n  the reference form.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n\n- **The reference must not be dereferenced early.** This is the whole function. An\n  implementation that resolves `reference` to values on entry can still return correct scalars\n  and will fail every composition — range endpoints, `SUM` over a computed column, dynamic named\n  ranges. The correctness of `INDEX` is not visible from its scalar results.\n- **Zero is a distinct branch, in each coordinate independently.** Four combinations\n  (both nonzero, row zero, column zero, both zero), and the both-zero case is meaningful only in\n  the reference form.\n- **Missing is a third state alongside zero and a positive index.** The one-dimensional\n  convenience means an implementation must know whether the argument was omitted, not merely\n  what its value was — which is exactly the Missing-versus-Empty distinction the shared model\n  insists on carrying to the call boundary.\n- **Index coercion has a documented shape in the reference implementation**: the index is\n  coerced to a number and rejected unless it is finite, non-negative and integral. Non-negative\n  rather than positive, because zero is legal — an implementation that validates `> 0` breaks\n  the whole-axis form.\n- **`area_num` selection precedes coordinate bounds checking**, since the bounds depend on which\n  area was selected. Doing it in the other order range-checks against the wrong rectangle.\n- **The array-selector path** in the reference implementation (a selector that may be a scalar\n  or an array) is the seam where dynamic-array behaviour enters. It is also the least\n  established part of this page.\n\n\n",
    "quirks": "\n### The two forms\n\n\nMicrosoft's documentation presents `INDEX` as two functions sharing a name.\n\n### Array form — `INDEX(array, row_num, [column_num])`\n\nOperates on an array value and returns a value (or, with a zero coordinate, an array). This is\nthe form you get when the first argument is an array constant, an array-valued expression, or a\nrange in a context where the result is consumed as a value.\n\nMicrosoft documents a convenience for one-dimensional inputs: if `array` has only one row or\nonly one column, the corresponding index argument is optional. So for a column `a`,\n`INDEX(a, 5)` means the fifth element — the missing `column_num` is not defaulted to 1 by\naccident, it is defined away because there is only one column.\n\n### Reference form — `INDEX(reference, row_num, [column_num], [area_num])`\n\nOperates on a reference and returns a reference. It gains a fourth argument, `area_num`, which\nselects which rectangle of a multi-area reference to index into; Microsoft documents the default\nas area 1. This is the form that composes with the reference algebra.\n\nThe two forms are not selected by a mode flag. Which one applies follows from what the first\nargument is and from what the calling context does with the result — which is exactly why\n`INDEX` feels different in different formulas, and why the reference-returning behaviour\nsurprises people who have only used the array form.\n\nThe practical consequences of the reference form are worth listing explicitly, because they are\nthe reason experienced modellers reach for `INDEX`:\n\n- **As a range endpoint.** `SUM(A1:INDEX(A:A, n))` sums from `A1` to a computed last row. The\n  range operator needs references on both sides; because `INDEX` supplies one, this works, and\n  it recomputes only when its inputs change.\n- **As a non-volatile `OFFSET`.** `OFFSET` is volatile: it recalculates on every recalculation\n  of the workbook. `INDEX` is recorded `volatility_class: NonVolatile`. For dynamic-range\n  definitions this is the difference between a workbook that recalculates lazily and one that\n  does not.\n- **As a target for functions that require a range**, such as those that need a reference rather\n  than its contents.\n\n`INDEX` is sometimes described as usable \"on the left of an assignment\", which is a loose way of\nsaying that it designates a location rather than a value. The worksheet has no assignment, so\nthe accurate statement is the one above: it returns a reference, and references are what\nlocation-consuming constructs need.\n\n\n\n### Result and edge cases\n\n\nReturn kind: a scalar, an `Array`, or a `Reference`, depending on form and on whether a\ncoordinate is zero.\n\n- **Both coordinates zero, reference form** — the whole reference (or the whole selected area).\n- **One coordinate zero** — a whole row or column. In the array form this is an array that\n  spills in modern Excel and required array entry historically; in the reference form it is a\n  reference to that row or column, which is the version that composes with `SUM` and the range\n  operator.\n- **Single-cell result in the reference form.** It is still a reference; the surrounding\n  expression decides whether it is dereferenced. A bare `INDEX` in a cell displays the value.\n- **Blank located cell.** Empty is admitted at the raw-return boundary but not at the published\n  one, so an `INDEX` onto an empty cell publishes as numeric zero rather than as blank — the\n  general normalization described in [the value universe](../model/01-value-universe.md), not\n  something `INDEX` decides.\n- **Error in the located cell** is simply the result.\n- **Array-valued coordinates.** The reference implementation's kernel carries both a scalar\n  selector and an array selector, so a vector of row numbers is a shape its structure\n  anticipates. What Excel returns for `INDEX(a, {1;3})` — a spilled vector, an implicit\n  intersection, or an error — is not established here, and it differs between the pre- and\n  post-dynamic-array eras.\n- **Implicit intersection.** In pre-dynamic-array Excel, an `INDEX` result that was an array or\n  multi-cell reference in a scalar context underwent implicit intersection; modern Excel spills\n  instead unless `@` is written. Formulas migrated from older workbooks carry the `@` marker for\n  exactly this reason, and the difference is a compatibility question rather than a semantic\n  one.\n\n\n\n### Errors\n\n\nMicrosoft's page documents:\n\n- `#REF!` when `row_num`, `column_num` or `area_num` is out of range for the given array or\n  reference — including an `area_num` larger than the number of areas present.\n- `#VALUE!` for arguments that are not usable as indices.\n\nThe split follows the same logic as `HLOOKUP`'s: a coordinate that points outside the data is a\nreference failure; a coordinate that is not a usable number is a value failure. The reference\nimplementation's error enumeration mirrors this shape, carrying distinct out-of-bounds and\ninvalid-index cases.\n\nAn error value supplied as an argument propagates under the universal rule in\n[coercion and lifting](../model/02-coercion-and-lifting.md).\n\n\n",
    "sources": "- Microsoft, INDEX function —\n  <https://support.microsoft.com/en-us/office/index-function-a5dcf0dd-996d-40a4-a822-b56b061328bd>\n  (the array and reference forms, the zero-coordinate whole-row/whole-column rule, the\n  one-dimensional omissible-argument convenience, `area_num` and its default, and the `#REF!`\n  and `#VALUE!` conditions).\n- Handbook `content/model/01-value-universe.md` (reference kind and shapes; Missing versus\n  Empty; the raw-return versus published-result boundary).\n- Handbook `content/model/02-coercion-and-lifting.md` (error propagation; reference resolution\n  as an explicit step).\n- Handbook `content/model/03-call-pipeline.md` (`RefsVisibleInAdapter`; reference-sensitive\n  functions returning references; operators as functions, including the range operator).\n- Handbook `data/functions/FUNC.INDEX.json` and `data/presence/FUNC.INDEX.json` (signature,\n  arity 2–4, classification axes, implementing module).\n\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`INDEX` retrieves what sits at given coordinates. Stated that plainly it sounds like array\nsubscripting, and for the simple call it is: `INDEX(a, 2, 3)` is the element in the second row\nand third column of `a`.\n\nTwo things lift it above subscripting, and between them they account for nearly everything\n`INDEX` is used for:\n\n1. **A zero coordinate means \"the whole axis\".** `INDEX(a, 0, 3)` is the entire third column;\n   `INDEX(a, 2, 0)` is the entire second row. Zero is not an out-of-range index, it is a\n   quantifier.\n2. **Given a reference, `INDEX` returns a reference** — not the reference's value. That is why\n   `INDEX` can appear as an endpoint of the range operator, be handed to functions that require\n   a range, and serve as a non-volatile substitute for `OFFSET`.\n\n\n### Arguments\n\n\n| Argument | Meaning |\n|---|---|\n| `array` / `reference` | The data to index into. An array value in the array form; a reference — possibly multi-area — in the reference form. Required. |\n| `row_num` | Which row, counting from 1 within the array or area. Zero means the whole column axis. Required by arity, though Microsoft documents it as omissible for one-dimensional inputs. |\n| `column_num` | Which column, counting from 1. Zero means the whole row axis. Optional. |\n| `area_num` | Reference form only: which area of a multi-area reference. Optional; documented default 1. |\n\nPositions that are commonly misunderstood:\n\n- **Coordinates are relative to the array or area, not to the worksheet.** `INDEX(C5:E9, 1, 1)`\n  is `C5`, not `A1`.\n- **Zero versus omitted.** These are different: zero selects a whole axis; omitted (Missing)\n  invokes the one-dimensional convenience or the documented default. The value model keeps\n  Missing distinct from every other \"nothing\"\n  ([value universe](../model/01-value-universe.md)), and `INDEX` is one of the functions where\n  the distinction is load-bearing rather than pedantic.\n- **`area_num` exists only in the reference form**, and a multi-area reference passed inline\n  needs the double-parenthesis grammar described on the `AREAS` page, because the comma would\n  otherwise separate arguments.\n\n\n"
  },
  "signature": {
    "display": "INDEX(array, row_num, [column_num], [area_num])",
    "parameters": [
      {
        "description": null,
        "name": "array",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "row_num",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "column_num",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "area_num",
        "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": "RefsVisibleInAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "None",
        "fec_dependency_profile": "RefOnly",
        "host_interaction_class": "WorkbookState",
        "kernel_signature_class": "Custom",
        "rich_value_usage": "RichBlind",
        "surface_fec_dependency_profile": "RefOnly",
        "thread_safety_class": "SafePure",
        "volatility_class": "NonVolatile"
      },
      "descriptions": {
        "long": null,
        "short": "The value or reference at a given row and column of an array or range",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Uses an index to choose a value from a reference or array",
        "microsoft_url": "https://support.microsoft.com/en-us/office/index-function-a5dcf0dd-996d-40a4-a822-b56b061328bd"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "INDEX"
        },
        {
          "locale": "bg-BG",
          "name": "INDEX"
        },
        {
          "locale": "cs-CZ",
          "name": "INDEX"
        },
        {
          "locale": "da-DK",
          "name": "INDEX"
        },
        {
          "locale": "de-DE",
          "name": "INDEX"
        },
        {
          "locale": "el-GR",
          "name": "INDEX"
        },
        {
          "locale": "en-AU",
          "name": "INDEX"
        },
        {
          "locale": "en-GB",
          "name": "INDEX"
        },
        {
          "locale": "en-US",
          "name": "INDEX"
        },
        {
          "locale": "es-ES",
          "name": "INDEX"
        },
        {
          "locale": "et-EE",
          "name": "INDEX"
        },
        {
          "locale": "fi-FI",
          "name": "HAKEMISTO"
        },
        {
          "locale": "fr-FR",
          "name": "INDEX"
        },
        {
          "locale": "he-IL",
          "name": "INDEX"
        },
        {
          "locale": "hr-HR",
          "name": "INDEX"
        },
        {
          "locale": "hu-HU",
          "name": "INDEX"
        },
        {
          "locale": "id-ID",
          "name": "INDEX"
        },
        {
          "locale": "it-IT",
          "name": "INDEX"
        },
        {
          "locale": "ja-JP",
          "name": "INDEX"
        },
        {
          "locale": "ko-KR",
          "name": "INDEX"
        },
        {
          "locale": "lt-LT",
          "name": "INDEX"
        },
        {
          "locale": "lv-LV",
          "name": "INDEX"
        },
        {
          "locale": "nb-NO",
          "name": "INDEX"
        },
        {
          "locale": "nl-NL",
          "name": "INDEX"
        },
        {
          "locale": "pl-PL",
          "name": "INDEX"
        },
        {
          "locale": "pt-BR",
          "name": "INDEX"
        },
        {
          "locale": "pt-PT",
          "name": "INDEX"
        },
        {
          "locale": "ro-RO",
          "name": "INDEX"
        },
        {
          "locale": "ru-RU",
          "name": "INDEX"
        },
        {
          "locale": "sk-SK",
          "name": "INDEX"
        },
        {
          "locale": "sl-SI",
          "name": "INDEX"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "INDEX"
        },
        {
          "locale": "sv-SE",
          "name": "INDEX"
        },
        {
          "locale": "th-TH",
          "name": "INDEX"
        },
        {
          "locale": "tr-TR",
          "name": "İNDİS"
        },
        {
          "locale": "uk-UA",
          "name": "INDEX"
        },
        {
          "locale": "vi-VN",
          "name": "INDEX"
        },
        {
          "locale": "zh-CN",
          "name": "INDEX"
        },
        {
          "locale": "zh-HK",
          "name": "INDEX"
        },
        {
          "locale": "zh-TW",
          "name": "INDEX"
        }
      ],
      "signature": {
        "display": "INDEX(array, row_num, [column_num], [area_num])",
        "parameters": [
          {
            "description": null,
            "name": "array",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "row_num",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "column_num",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "area_num",
            "optional": true,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "INDEX",
      "version_marker": null,
      "xlcall": {
        "code": "29",
        "symbol": "xlfIndex"
      }
    },
    "microsoft": "https://support.microsoft.com/en-us/office/index-function-a5dcf0dd-996d-40a4-a822-b56b061328bd"
  },
  "try_it": {
    "formula": "=INDEX({10,20;30,40},2,1)"
  },
  "url": "https://handbook.dnacalc.com/functions/INDEX.html",
  "variants": [],
  "versions": []
}