{
  "category": "Lookup and reference functions",
  "display_name": "CHOOSE",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.CHOOSE",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 40 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 40 recorded answers",
    "workbook_corpus": {
      "cells": 41,
      "matched": 40,
      "pending": 1
    }
  },
  "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#L191-L203",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/lookup.rs#L1695-L1725"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "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#L191-L203",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 40 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.CHOOSE.json",
  "name": "CHOOSE",
  "notes": [
    {
      "basis": "One recorded array reading, with ROWS 1 and COLUMNS 2 from observer cells, and one scalar ISREF reading with a reference to another workbook.",
      "documentation": null,
      "evidence": [
        {
          "commit": "eceb809985e244e9d0a20f905e58fe57b8741ed8",
          "locator": "sheet fn2_q193",
          "note": null,
          "path": "crates/calc-func/tests/captures/fn2_questions/oracle.capture.json",
          "repository": "DnaCalc"
        },
        {
          "commit": "1ec418b2c1301d36309d717999512776b1d8630d",
          "locator": "dc-b1l.24",
          "note": "review record",
          "path": ".beads/issues.jsonl",
          "repository": "DnaCalc"
        }
      ],
      "functions": [
        "FUNC.CHOOSE"
      ],
      "inferred": "That a scalar index over an empty cell gives ISBLANK TRUE is inferred from the ISREF reading. No ISBLANK reading of it is recorded.",
      "kind": "quirk",
      "note_id": "FN-CHOOSE-001",
      "open": [],
      "recorded_on": "2026-11-04",
      "repros": [
        {
          "call": "=ISBLANK(CHOOSE({1,2},Data!Z1,Data!Z2))",
          "correct": null,
          "excel": {
            "bits": null,
            "display": "{FALSE,FALSE}",
            "kind": "array"
          },
          "input_route": "formula-literal",
          "inputs": [],
          "recorded_in": "Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZA",
          "source": {
            "commit": "eceb809985e244e9d0a20f905e58fe57b8741ed8",
            "locator": "sheet fn2_q193, row 20, column 10",
            "note": null,
            "path": "crates/calc-func/tests/captures/fn2_questions/oracle.capture.json",
            "repository": "DnaCalc"
          }
        },
        {
          "call": "=ISREF(CHOOSE(1,[ylr-source.xlsx]Sheet1!A1))",
          "correct": null,
          "excel": {
            "bits": null,
            "display": "TRUE",
            "kind": "logical"
          },
          "input_route": "formula-literal",
          "inputs": [],
          "recorded_in": "Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZA",
          "source": {
            "commit": "2d0eddcac86413014643af81d646581d54ba57bc",
            "locator": "sheet Main, row 54, column 1",
            "note": "The recorded formula names the source workbook by its full path",
            "path": "crates/calc-host/tests/captures/dc_ylr/oracle.capture.json",
            "repository": "DnaCalc"
          }
        }
      ],
      "schema": "efh.function-note/v1",
      "statement": "When an array index_num lifts CHOOSE in dynamic-array Excel, selected empty cells come back as the number 0 rather than as blank references, so ISBLANK over them is FALSE. With a scalar index the selected reference survives: ISREF(CHOOSE(1,ref)) was recorded TRUE.",
      "status": "measured",
      "title": "An array index in CHOOSE turns selected blank cells into 0"
    }
  ],
  "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- **`SWITCH`** is the modern equivalent for matching a value against a list of cases. Where\n  `CHOOSE` indexes by position, `SWITCH` matches by equality and supports a default. New code\n  that is really doing case analysis should use `SWITCH`.\n- **`IFS`** — `CHOOSE`'s module sibling in the reference implementation — selects by the first\n  satisfied condition rather than by ordinal.\n- **`INDEX`** is the near-neighbour that indexes into *data* rather than into an argument list.\n  If your candidates live in cells, `INDEX` is the right tool; `CHOOSE` is for candidates that\n  live in the formula.\n- **`CHOOSECOLS` and `CHOOSEROWS`** share a prefix and nothing else. They select columns or\n  rows from a single array; they are dynamic-array reshapers, not branch selectors. The naming\n  collision is the most reliable source of confusion in this corner of the catalog.\n- **`LOOKUP` with a constant vector** does the same job for larger candidate lists and keeps the\n  candidates out of the formula text.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n\n- **Selection must precede evaluation for the scalar case, and cannot for the array case.**\n  Those are two different execution strategies for one function, and the documented array\n  caveat is the seam between them. An implementation that always evaluates all arguments will\n  agree with Excel on results and disagree on cost and on error visibility for branches that\n  throw; an implementation that always defers will disagree with the documented array\n  behaviour.\n- **The reference must survive selection.** Dereferencing a `value` argument before returning it\n  breaks `SUM(CHOOSE(2, A1:A10, B1:B10))` in a way that unit tests on scalars will never catch.\n  This is the practical content of `RefsVisibleInAdapter` for this function.\n- **The 254-value ceiling is documented in terms of `index_num`, and the arity ceiling is 255\n  arguments.** Those are two statements of one limit; an implementation should enforce it in\n  one place.\n- The reference implementation places `CHOOSE` with `IFS` in a shared module, which is a\n  statement about code organization rather than about Excel: the two functions share a\n  selector skeleton.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nThe return kind is whatever the selected argument is: a scalar, an array, or a reference. With a\nscalar `index_num` there is no coercion of the selected value — that is what \"returns it verbatim\"\nmeans for a branch selector. An array `index_num` differs, as the first item below says.\n\nSpecific behaviours:\n\n- **Array `index_num`.** Microsoft documents that if `index_num` is an array, every value is\n  evaluated when `CHOOSE` is evaluated. Read that carefully: it is a statement about\n  *evaluation*, not about the result. The practical consequence is that `CHOOSE` is not lazy\n  in the array case, so side conditions you were relying on to stay unevaluated (a branch that\n  would error, a slow branch) are evaluated anyway. In dynamic-array Excel `CHOOSE` then returns\n  an array of selections, and selected empty cells come back as the number 0 rather than as\n  blank references (FN-CHOOSE-001).\n- **Reference results.** Because the selected argument can be a reference, `CHOOSE` composes\n  with range-consuming functions. Whether the result can serve as an endpoint of the range\n  operator (as `INDEX`'s reference form can) is an open question on this page.\n- **Omitted argument slots.** `CHOOSE(2, A1, , B1)` delivers the Missing marker into a value\n  slot. Missing and Empty are distinct at the call boundary\n  ([value universe](../model/01-value-universe.md)); what `CHOOSE` returns when the *selected*\n  slot is Missing is a genuine question, since Missing is not admitted at the published-result\n  boundary.\n- **`index_num` from text.** A direct text argument that reads as a number coerces under the\n  ordinary rules in [coercion and lifting](../model/02-coercion-and-lifting.md); text arriving\n  from a scanned cell is a different lane. `CHOOSE` is not an aggregate, so the direct/scan\n  asymmetry that governs `SUM` does not obviously apply — but \"does not obviously apply\" is not\n  a finding.\n\n\n\n### Errors\n\n\nMicrosoft's page documents the failure conditions in terms of `index_num`:\n\n- `index_num` less than 1, or greater than the number of values supplied, produces `#VALUE!`.\n- `index_num` that is a fraction is truncated to the lowest integer before being used, so\n  fractions are not by themselves an error.\n\n",
    "sources": "- Microsoft, CHOOSE function —\n  <https://support.microsoft.com/en-us/office/choose-function-fc5c184f-cb62-4ec7-a46e-38653b98f5bc>\n  (the 1–254 `index_num` range, truncation of fractional indices, `#VALUE!` for out-of-range\n  indices, and the array-`index_num` evaluation note).\n- Handbook `content/model/01-value-universe.md` (Missing versus Empty; reference kind).\n- Handbook `content/model/02-coercion-and-lifting.md` (direct-argument coercion; error\n  propagation).\n- Handbook `data/functions/FUNC.CHOOSE.json` and `data/presence/FUNC.CHOOSE.json` (arity,\n  classification axes, implementing module shared with `IFS`).\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`CHOOSE(index_num, value1, value2, …)` is positional selection: it returns the argument at\nordinal position `index_num` in the value list. `index_num` of 1 selects `value1`, 2 selects\n`value2`, and so on. That is the entire semantic core.\n\nTwo properties make it more than a table lookup written sideways.\n\n\n### Arguments\n\n\n| Argument | Meaning |\n|---|---|\n| `index_num` | Which value to return, counting from 1. Microsoft documents that it must be a number between 1 and 254, a formula yielding such a number, or a reference to a cell containing one. Microsoft further documents that a fractional `index_num` is truncated to the lowest integer before use. |\n| `value1` | The first selectable argument. Required. |\n| `value2`, … | Further selectable arguments, up to the arity ceiling. Optional. |\n\nThe arity is 2 to 255 — one index plus up to 254 values, which is exactly the ceiling\nMicrosoft's documented `index_num` range implies.\n\n`value` arguments may be numbers, text, cell references, defined names, formulas, functions, or\n— importantly — ranges. The misunderstanding to head off: **the values are not a list you index\ninto, they are argument slots.** You cannot pass an array of candidates in one argument and have\n`CHOOSE` pick from inside it; `CHOOSE({10,20,30}, …)` indexes the argument list with an array of\nindices, which is a different operation (see below).\n\n\n"
  },
  "signature": {
    "display": "CHOOSE(index_num, value1, [value2], ...)",
    "parameters": [
      {
        "description": null,
        "name": "index_num",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "value1",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "value2",
        "optional": true,
        "repeats": true
      }
    ],
    "trailing_repeats": true
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 255,
        "min": 2
      },
      "category": "Lookup and reference functions",
      "classification": {
        "arg_preparation_profile": "RefsVisibleInAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "SelectorBranch",
        "fec_dependency_profile": "None",
        "host_interaction_class": "None",
        "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 at a given position in a list of arguments",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Chooses a value from a list of values",
        "microsoft_url": "https://support.microsoft.com/en-us/office/choose-function-fc5c184f-cb62-4ec7-a46e-38653b98f5bc"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "CHOOSE"
        },
        {
          "locale": "bg-BG",
          "name": "CHOOSE"
        },
        {
          "locale": "cs-CZ",
          "name": "ZVOLIT"
        },
        {
          "locale": "da-DK",
          "name": "VÆLG"
        },
        {
          "locale": "de-DE",
          "name": "WAHL"
        },
        {
          "locale": "el-GR",
          "name": "CHOOSE"
        },
        {
          "locale": "en-AU",
          "name": "CHOOSE"
        },
        {
          "locale": "en-GB",
          "name": "CHOOSE"
        },
        {
          "locale": "en-US",
          "name": "CHOOSE"
        },
        {
          "locale": "es-ES",
          "name": "ELEGIR"
        },
        {
          "locale": "et-EE",
          "name": "CHOOSE"
        },
        {
          "locale": "fi-FI",
          "name": "VALITSE.INDEKSI"
        },
        {
          "locale": "fr-FR",
          "name": "CHOISIR*"
        },
        {
          "locale": "he-IL",
          "name": "CHOOSE"
        },
        {
          "locale": "hr-HR",
          "name": "CHOOSE"
        },
        {
          "locale": "hu-HU",
          "name": "VÁLASZT"
        },
        {
          "locale": "id-ID",
          "name": "CHOOSE"
        },
        {
          "locale": "it-IT",
          "name": "CHOOSE"
        },
        {
          "locale": "ja-JP",
          "name": "CHOOSE"
        },
        {
          "locale": "ko-KR",
          "name": "CHOOSE"
        },
        {
          "locale": "lt-LT",
          "name": "CHOOSE"
        },
        {
          "locale": "lv-LV",
          "name": "CHOOSE"
        },
        {
          "locale": "nb-NO",
          "name": "VELG"
        },
        {
          "locale": "nl-NL",
          "name": "KIEZEN"
        },
        {
          "locale": "pl-PL",
          "name": "WYBIERZ"
        },
        {
          "locale": "pt-BR",
          "name": "ESCOLHER"
        },
        {
          "locale": "pt-PT",
          "name": "SELECIONAR"
        },
        {
          "locale": "ro-RO",
          "name": "CHOOSE"
        },
        {
          "locale": "ru-RU",
          "name": "ВЫБОР"
        },
        {
          "locale": "sk-SK",
          "name": "CHOOSE"
        },
        {
          "locale": "sl-SI",
          "name": "CHOOSE"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "ODABERITE"
        },
        {
          "locale": "sv-SE",
          "name": "VÄLJ"
        },
        {
          "locale": "th-TH",
          "name": "CHOOSE"
        },
        {
          "locale": "tr-TR",
          "name": "ELEMAN işlevi"
        },
        {
          "locale": "uk-UA",
          "name": "CHOOSE"
        },
        {
          "locale": "vi-VN",
          "name": "CHOOSE"
        },
        {
          "locale": "zh-CN",
          "name": "CHOOSE"
        },
        {
          "locale": "zh-HK",
          "name": "CHOOSE"
        },
        {
          "locale": "zh-TW",
          "name": "CHOOSE"
        }
      ],
      "signature": {
        "display": "CHOOSE(index_num, value1, [value2], ...)",
        "parameters": [
          {
            "description": null,
            "name": "index_num",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "value1",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "value2",
            "optional": true,
            "repeats": true
          }
        ],
        "trailing_repeats": true
      },
      "surface_name": "CHOOSE",
      "version_marker": null,
      "xlcall": {
        "code": "100",
        "symbol": "xlfChoose"
      }
    },
    "microsoft": "https://support.microsoft.com/en-us/office/choose-function-fc5c184f-cb62-4ec7-a46e-38653b98f5bc"
  },
  "try_it": {
    "formula": "=CHOOSE(2,\"a\",\"b\",\"c\")"
  },
  "url": "https://handbook.dnacalc.com/functions/CHOOSE.html",
  "variants": [],
  "versions": [
    {
      "behaviour": "=ISBLANK(CHOOSE({1,2},Data!Z1,Data!Z2)) returned {FALSE,FALSE}. =ISREF(CHOOSE(1,[ylr-source.xlsx]Sheet1!A1)) returned TRUE. Inputs were supplied through formula literals. These are controls from this environment, not a same-input comparison with another build.",
      "excel_build": "16.0.20527.20088",
      "observations": [
        {
          "call": "=ISBLANK(CHOOSE({1,2},Data!Z1,Data!Z2))",
          "excel": {
            "bits": null,
            "display": "{FALSE,FALSE}",
            "kind": "array"
          },
          "input_route": "formula-literal",
          "inputs": [],
          "recorded_in": "Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZA"
        },
        {
          "call": "=ISREF(CHOOSE(1,[ylr-source.xlsx]Sheet1!A1))",
          "excel": {
            "bits": null,
            "display": "TRUE",
            "kind": "logical"
          },
          "input_route": "formula-literal",
          "inputs": [],
          "recorded_in": "Excel 16.0.20527.20088 Current Channel, Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZA"
        }
      ],
      "platform": "Windows 64-bit (NT 10.0.26200), x86-64, AMD Ryzen 7 4800H, en-ZA",
      "sources": [
        "https://github.com/DnaCalc/ExcelFunctionsHandbook/blob/3345a87/content/notes/FN-CHOOSE-001.json"
      ]
    }
  ]
}