{
  "category": "Our 10 featured functions",
  "display_name": "UNIQUE",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.UNIQUE",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 5 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 5 recorded answers",
    "workbook_corpus": {
      "cells": 5,
      "matched": 5
    }
  },
  "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/arrays.rs#L643-L645",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/arrays.rs#L359-L381",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/arrays.rs#L484-L496",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/arrays.rs#L498-L520",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/arrays.rs#L522-L594",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/comparison.rs#L414-L427",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/comparison/sort_key.rs#L519-L526"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/arrays::prepared",
        "catalogue/arrays::prepared_one",
        "catalogue/arrays::as_array",
        "catalogue/arrays::integer",
        "catalogue/arrays::flag",
        "catalogue/arrays::kind",
        "catalogue/arrays::order",
        "catalogue/comparison::numbers",
        "catalogue/comparison::in_band",
        "catalogue/comparison::Rounded::up",
        "catalogue/comparison::Roundings::of",
        "catalogue/comparison::Roundings::disjoint",
        "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",
        "decimal::low32",
        "decimal::Natural::from_u64",
        "decimal::Natural::pow10",
        "decimal::Natural::normalize",
        "decimal::Natural::is_zero",
        "decimal::Natural::mul_add_small",
        "decimal::Natural::times_pow10",
        "decimal::Natural::times_pow5",
        "decimal::Natural::times_pow2",
        "decimal::ExactDecimal::binary",
        "ported/dynamic_array_reshape_family::coerce_prepared_to_number"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/arrays.rs#L643-L645",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 5 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.UNIQUE.json",
  "name": "UNIQUE",
  "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- **`SORT`** orders; `UNIQUE` deduplicates. `SORT(UNIQUE(x))` is the canonical pairing.\n- **`FILTER`** selects by predicate; `UNIQUE` selects by novelty. `UNIQUE(FILTER(...))` is the\n  common pipeline.\n- **`COUNTIF`** is the classic pre-dynamic-array way to compute both behaviours:\n  `COUNTIF(range, x) = 1` is the `exactly_once` test, and a running `COUNTIF` over the prefix is\n  the distinct test. Anyone maintaining older workbooks will meet these.\n- **`TOCOL(…, 1)`** removes blanks, which is often what a reader actually wanted when they\n  reached for `UNIQUE` on a padded column.\n- **Data ▸ Remove Duplicates** is the destructive command form; `UNIQUE` is the formula form\n  and leaves the source intact.\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n- Row equality, not cell equality, is the primitive. It needs a defined comparison for every\n  value kind, including blanks and errors, and it needs to be consistent with whatever equality\n  the rest of the engine uses — or to be deliberately different, and recorded as such.\n- Order of first appearance must be preserved. A hash-set implementation that returns iteration\n  order will be wrong on almost every input and right on the tests.\n- `exactly_once` requires counting, not just membership: it is a second pass (or a count-keyed\n  map), and it cannot be short-circuited on first sight of a row.\n- The empty result is a real case and needs a decided outcome rather than a panic or an empty\n  array that later code cannot represent.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nThe return kind is an array — a subset of the input's rows (or columns), full width, spilled.\n\n- **The result can be empty.** `UNIQUE(x, , TRUE)` over data where every row repeats has\n  nothing to return. Excel's convention for an empty array result is `#CALC!` (see\n  [the value universe](../model/01-value-universe.md)); the Handbook has not verified that\n  `UNIQUE` uses it.\n- **Blanks are values.** A blank row is a row, and it will appear in the distinct set. This\n  surprises readers who apply `UNIQUE` to a whole column and get a blank entry from the unused\n  rows below the data — the usual remedy being `TRIMRANGE` or a `FILTER` first.\n- **Errors inside the array** are values too; whether two identical error values compare equal\n  is unverified.\n- **Shape.** Row mode returns full-width rows; column mode returns full-height columns. A\n  single-element result must still be array-shaped — the `ROWS`/`TYPE` probe on the `ROWS` page\n  explains why that distinction is observable.\n- Dynamic-array publication and `#SPILL!` are host-side adaptation, not `UNIQUE` semantics.\n\n\n\n### Errors\n\n\nMicrosoft documents one error for `UNIQUE`: `#REF!` in the cross-workbook dynamic-array case,\nwhen a linked source workbook is closed — dynamic arrays between workbooks are supported only\nwhile both are open.\n\nNo other error is documented. `#SPILL!` arises from publication as for any dynamic array, and\n`#CALC!` is Excel's general marker for an empty array result; neither is stated on the `UNIQUE`\npage, and the Handbook does not assert them for this function.\n\n\n",
    "sources": "- Microsoft, *UNIQUE function* —\n  <https://support.microsoft.com/en-us/office/unique-function-c5ab87fd-30a3-4ce9-9d1a-40204fb85e1e>\n  (syntax, the `by_col` and `exactly_once` defaults, the explicit distinct-versus-database-unique\n  wording, and the cross-workbook `#REF!` condition). Retrieved for this page.\n- Handbook `content/model/01-value-universe.md` (the `#CALC!` empty-array convention) and\n  `content/model/03-call-pipeline.md`.\n- Handbook `data/functions/FUNC.UNIQUE.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`UNIQUE` removes repetition along one axis. It compares **whole rows** (or, with `by_col` set,\nwhole columns) and returns a subset of them, in their original order of first appearance.\n\nThe flag `exactly_once` selects between two genuinely different operations, and Microsoft's\ndocumentation is careful about the distinction:\n\n- **`exactly_once` = `FALSE` (default): distinct.** Every row that appears at least once\n  appears once in the output. From `A, B, A, C` you get `A, B, C`.\n- **`exactly_once` = `TRUE`: unique in the database sense.** Only rows that appear *exactly*\n  once survive. From `A, B, A, C` you get `B, C` — `A` is gone entirely, not collapsed.\n\nThese are not two settings of one filter; they are \"distinct\" and \"singletons\", and confusing\nthem silently drops data. The English word \"unique\" covers both, which is precisely why the\nargument exists.\n\nTwo structural points:\n\n- **The unit of comparison is a whole row, not a cell.** `UNIQUE(A1:C100)` treats two rows as\n  equal only when all three of their cells match. To deduplicate on one column you pass that\n  column, or you rebuild the row afterwards.\n\n\nWhat \"equal\" means for two rows — case sensitivity for text, numeric near-equality, whether a\nblank equals a zero, whether two `#N/A` values are equal — is the substantive open question on\nthis page. The documentation does not state it.\n\n\n\n### Arguments\n\n\nMicrosoft documents `UNIQUE(array, [by_col], [exactly_once])`.\n\n| Argument | Default | Meaning |\n|---|---|---|\n| `array` | required | The range or array from which to return unique rows or columns |\n| `by_col` | `FALSE` | `TRUE` compares columns; `FALSE` or omitted compares rows |\n| `exactly_once` | `FALSE` | `TRUE` returns only rows/columns occurring exactly once; `FALSE` returns all distinct ones |\n\nThe commonly misunderstood position is the third. Because both optional arguments are logicals\nwith `FALSE` defaults, `UNIQUE(A1:A9, TRUE)` reads at a glance like \"yes, unique\" but actually\nmeans \"compare columns\" — which, for a single-column input, returns the whole column unchanged.\nThe singleton behaviour needs the *third* argument: `UNIQUE(A1:A9, , TRUE)`.\n\n\n"
  },
  "signature": {
    "display": "UNIQUE(array, [by_col], [exactly_once])",
    "parameters": [
      {
        "description": null,
        "name": "array",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "by_col",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "exactly_once",
        "optional": true,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 3,
        "min": 1
      },
      "category": "Our 10 featured functions",
      "classification": {
        "arg_preparation_profile": "ValuesOnlyPreAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "None",
        "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 distinct rows or columns of an array, or those that occur only once",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Use this function to return a list of unique values in a list or range.",
        "microsoft_url": "https://support.microsoft.com/en-us/office/unique-function-c5ab87fd-30a3-4ce9-9d1a-40204fb85e1e"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "UNIQUE"
        },
        {
          "locale": "bg-BG",
          "name": "UNIQUE"
        },
        {
          "locale": "cs-CZ",
          "name": "UNIQUE"
        },
        {
          "locale": "da-DK",
          "name": "ENTYDIGE"
        },
        {
          "locale": "de-DE",
          "name": "UNIQUE"
        },
        {
          "locale": "el-GR",
          "name": "UNIQUE"
        },
        {
          "locale": "en-AU",
          "name": "UNIQUE"
        },
        {
          "locale": "en-GB",
          "name": "UNIQUE"
        },
        {
          "locale": "en-US",
          "name": "UNIQUE"
        },
        {
          "locale": "es-ES",
          "name": "UNICOS"
        },
        {
          "locale": "et-EE",
          "name": "UNIQUE"
        },
        {
          "locale": "fi-FI",
          "name": "AINUTLAATUINEN"
        },
        {
          "locale": "fr-FR",
          "name": "UNIQUE*"
        },
        {
          "locale": "he-IL",
          "name": "UNIQUE"
        },
        {
          "locale": "hr-HR",
          "name": "UNIQUE"
        },
        {
          "locale": "hu-HU",
          "name": "EGYEDI"
        },
        {
          "locale": "id-ID",
          "name": "UNIQUE"
        },
        {
          "locale": "it-IT",
          "name": "UNIQUE"
        },
        {
          "locale": "ja-JP",
          "name": "UNIQUE"
        },
        {
          "locale": "ko-KR",
          "name": "UNIQUE"
        },
        {
          "locale": "lt-LT",
          "name": "UNIQUE"
        },
        {
          "locale": "lv-LV",
          "name": "UNIQUE"
        },
        {
          "locale": "nb-NO",
          "name": "UNIQUE"
        },
        {
          "locale": "nl-NL",
          "name": "UNIEK"
        },
        {
          "locale": "pl-PL",
          "name": "UNIKATOWE"
        },
        {
          "locale": "pt-BR",
          "name": "UNIQUE"
        },
        {
          "locale": "pt-PT",
          "name": "EXCLUSIVO"
        },
        {
          "locale": "ro-RO",
          "name": "UNIQUE"
        },
        {
          "locale": "ru-RU",
          "name": "УНИК"
        },
        {
          "locale": "sk-SK",
          "name": "UNIQUE"
        },
        {
          "locale": "sl-SI",
          "name": "UNIQUE"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "UNIQUE"
        },
        {
          "locale": "sv-SE",
          "name": "UNIK"
        },
        {
          "locale": "th-TH",
          "name": "UNIQUE"
        },
        {
          "locale": "tr-TR",
          "name": "BENZERSİZ"
        },
        {
          "locale": "uk-UA",
          "name": "UNIQUE"
        },
        {
          "locale": "vi-VN",
          "name": "UNIQUE"
        },
        {
          "locale": "zh-CN",
          "name": "UNIQUE"
        },
        {
          "locale": "zh-HK",
          "name": "UNIQUE"
        },
        {
          "locale": "zh-TW",
          "name": "UNIQUE"
        }
      ],
      "signature": {
        "display": "UNIQUE(array, [by_col], [exactly_once])",
        "parameters": [
          {
            "description": null,
            "name": "array",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "by_col",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "exactly_once",
            "optional": true,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "UNIQUE",
      "version_marker": null,
      "xlcall": null
    },
    "microsoft": "https://support.microsoft.com/en-us/office/unique-function-c5ab87fd-30a3-4ce9-9d1a-40204fb85e1e"
  },
  "try_it": {
    "formula": "=UNIQUE({1;2;1})"
  },
  "url": "https://handbook.dnacalc.com/functions/UNIQUE.html",
  "variants": [],
  "versions": []
}