{
  "category": "Lookup and reference functions",
  "display_name": "GROUPBY",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.GROUPBY",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 428 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 428 recorded answers",
    "workbook_corpus": {
      "cells": 428,
      "matched": 428
    }
  },
  "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/grouping.rs#L795-L795",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/grouping.rs#L453-L565"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "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",
        "catalogue/grouping::Table::height",
        "catalogue/grouping::table",
        "catalogue/grouping::functions",
        "catalogue/grouping::whole",
        "catalogue/grouping::sort_entries",
        "catalogue/grouping::filter",
        "catalogue/grouping::kind",
        "catalogue/grouping::order",
        "catalogue/grouping::same",
        "catalogue/grouping::canonical",
        "catalogue/grouping::group",
        "catalogue/grouping::call",
        "catalogue/grouping::column",
        "catalogue/grouping::aggregate",
        "catalogue/grouping::text",
        "catalogue/grouping::headers",
        "catalogue/grouping::pairs",
        "catalogue/grouping::function_name",
        "catalogue/grouping::sort_groups",
        "catalogue/grouping::result",
        "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"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/grouping.rs#L795-L795",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 428 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.GROUPBY.json",
  "name": "GROUPBY",
  "notes": [],
  "schema": "efh.function-reference/v1",
  "section_order": [
    "what-it-does",
    "try-it",
    "quirks",
    "how-to-implement",
    "version-differences",
    "alternatives"
  ],
  "sections": {
    "alternatives": "\n[PIVOTBY](FUNC.PIVOTBY.md) adds column groups; [SUMIFS](FUNC.SUMIFS.md) computes a chosen scalar group; [PERCENTOF](FUNC.PERCENTOF.md) uses the second callback argument.\n\n\n",
    "how-to-implement": "\nValidate matching row counts, callable arguments and any Boolean filter. Resolve headers and remove filtered rows before grouping. Group rows by typed key tuples, preserve the represented key label, sort under the requested relationship and sort keys, then pass each group’s value column to the callback. Build requested subtotals/grand totals by aggregating their underlying rows, not by summing already aggregated cells. A two-argument callback also receives its comparison set. Recorded array callback results remain boxed within a result cell; do not silently flatten them. In the example east receives three and seven, west five and eleven.\n\nFor an average callback, a grand total must use source observations with their original counts. If east contains `3,7` and west contains only `11`, their averages are five and eleven, but the grand average is `(3+7+11)/3=7`. Averaging the two group results would incorrectly give eight. The same rule matters for COUNT, percent callbacks and custom lambdas.\n\n\n",
    "quirks": "\nAutomatic header inference can remove a first row when values begin with text then a number; specify field_headers when that ambiguity matters. Header modes zero through three distinguish no headers, hidden existing headers, generated headers and shown existing headers. Totals, hierarchy/table relationships, sorting and filtering affect output shape. Current recorded text keys are case-insensitive and retain the first spelling.\n\n| Option | Meaning |\n|---|---|\n| `field_headers` | `0` treats every row as data; `1` consumes a header; `2` generates labels; `3` consumes and displays a header. Omitted means infer. |\n| `total_depth` | `0` omits totals, `1` requests a grand total, deeper levels add subtotals. Negative values place totals before details. |\n| `filter_array` | One Boolean per source row, applied before aggregation. |\n| `field_relationship` | `0` keeps hierarchical key ordering; `1` treats keys as a table and excludes subtotals. |\n\nSubtotals need enough key columns. In the recorded current route, a filter admitting no rows gives `#VALUE!`; a blank output is not the universal empty-filter result.\n\n\n",
    "sources": "\n- [Microsoft: GROUPBY function](https://support.microsoft.com/en-us/excel/functions/groupby-function), opened 6 November 2026; syntax, documented argument rules and errors.\n- [DnaCalc implementation](https://github.com/DnaCalc/DnaCalc/blob/da3ecc4fb19a3a5529708c311d0e8f05688ac165/crates/calc-func/src/catalogue/grouping.rs); implementation steps and the limits identified in the text.\n\n",
    "try-it": "\nPut `east,west,east,west` in B2:B5 and `3,5,7,11` in C2:C5. `=GROUPBY(B2:B5,C2:C5,LAMBDA(v,SUM(v)),0,0)` returns the two group rows `east,10` and `west,16`. Explicit zero options mean no input headers and no totals.\n\nTo put the largest amount first, add `-2` as sort_order: `=GROUPBY(B2:B5,C2:C5,LAMBDA(v,SUM(v)),0,0,-2)`. The first output column is the group label and the second the aggregated amount, so this returns west before east. A negative sort index means descending.\n\n\n",
    "version-differences": "\nThe current source retains Excel 16.0 build 20527 COM observations from 30 October 2026: sixty grouping calls, plus separately described depth and multi-value controls. Those are one-build observations. No same-input difference against an earlier build is established here. Microsoft’s availability list is separate from these measurements.\n\n\n",
    "what-it-does": "\n`GROUPBY(row_fields,values,function,[field_headers],[total_depth],[sort_order],[filter_array],[field_relationship])` aggregates source rows by one or more key columns and spills a grouped table. The callback can be SUM, another supported function value, a LAMBDA or a vector of callbacks.\n\nThe key and value arguments are column-oriented tables with the same number of records. One key column groups by one label; several key columns describe levels such as region and product. Several value columns or a vector of callbacks can produce several aggregations.\n\n\n"
  },
  "signature": {
    "display": "GROUPBY(row_fields, values, function, [field_headers], [total_depth], [sort_order], [filter_array], [field_relationship])",
    "parameters": [
      {
        "description": "Grouping keys used to partition the input rows.",
        "name": "row_fields",
        "optional": false,
        "repeats": false
      },
      {
        "description": "Value vector or matrix aggregated within each group.",
        "name": "values",
        "optional": false,
        "repeats": false
      },
      {
        "description": "Current parked baseline supports the admitted grouped-aggregation callable/aggregate slice.",
        "name": "function",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "field_headers",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "total_depth",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "sort_order",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "filter_array",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "field_relationship",
        "optional": true,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 8,
        "min": 3
      },
      "category": "Lookup and reference functions",
      "classification": {
        "arg_preparation_profile": "ValuesOnlyPreAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "ReductionFold",
        "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": "The first widened tranche uses GROUPBY as the grouped-aggregation representative for witness rollout.",
        "short": "A summary table with values aggregated by the groups of one or more row fields",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Helps a user group, aggregate, sort, and filter data based on the fields you specify",
        "microsoft_url": "https://support.microsoft.com/en-us/office/groupby-function-5e08ae8c-6800-4b72-b623-c41773611505"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "GROUPBY"
        },
        {
          "locale": "bg-BG",
          "name": "GROUPBY"
        },
        {
          "locale": "cs-CZ",
          "name": "SESKUPITPODLE"
        },
        {
          "locale": "da-DK",
          "name": "GRUPPER.EFTER"
        },
        {
          "locale": "de-DE",
          "name": "GROUPBY"
        },
        {
          "locale": "el-GR",
          "name": "GROUPBY"
        },
        {
          "locale": "en-AU",
          "name": "GROUPBY"
        },
        {
          "locale": "en-GB",
          "name": "GROUPBY"
        },
        {
          "locale": "en-US",
          "name": "GROUPBY"
        },
        {
          "locale": "es-ES",
          "name": "AGRUPARPOR"
        },
        {
          "locale": "et-EE",
          "name": "GROUPBY"
        },
        {
          "locale": "fi-FI",
          "name": "JÄRJESTÄ.ARVOJEN.MUKAAN"
        },
        {
          "locale": "fr-FR",
          "name": "GROUPER.PAR*"
        },
        {
          "locale": "he-IL",
          "name": "GROUPBY"
        },
        {
          "locale": "hr-HR",
          "name": "GROUPBY"
        },
        {
          "locale": "hu-HU",
          "name": "CSOPORTOSÍTÁS.ALAP.SZERINT"
        },
        {
          "locale": "id-ID",
          "name": "GROUPBY"
        },
        {
          "locale": "it-IT",
          "name": "GROUPBY"
        },
        {
          "locale": "ja-JP",
          "name": "GROUPBY"
        },
        {
          "locale": "ko-KR",
          "name": "GROUPBY"
        },
        {
          "locale": "lt-LT",
          "name": "GROUPBY"
        },
        {
          "locale": "lv-LV",
          "name": "GROUPBY"
        },
        {
          "locale": "nb-NO",
          "name": "GROUPBY"
        },
        {
          "locale": "nl-NL",
          "name": "GROEPEREN.PER"
        },
        {
          "locale": "pl-PL",
          "name": "GRUPUJ.WEDŁUG"
        },
        {
          "locale": "pt-BR",
          "name": "GROUPBY"
        },
        {
          "locale": "pt-PT",
          "name": "AGRUPARPOR"
        },
        {
          "locale": "ro-RO",
          "name": "GROUPBY"
        },
        {
          "locale": "ru-RU",
          "name": "ГРУПППО"
        },
        {
          "locale": "sk-SK",
          "name": "GROUPBY"
        },
        {
          "locale": "sl-SI",
          "name": "GROUPBY"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "GROUPBY"
        },
        {
          "locale": "sv-SE",
          "name": "GRUPPERAEFTER"
        },
        {
          "locale": "th-TH",
          "name": "GROUPBY"
        },
        {
          "locale": "tr-TR",
          "name": "GRUPLAÖLÇÜT"
        },
        {
          "locale": "uk-UA",
          "name": "GROUPBY"
        },
        {
          "locale": "vi-VN",
          "name": "GROUPBY"
        },
        {
          "locale": "zh-CN",
          "name": "GROUPBY"
        },
        {
          "locale": "zh-HK",
          "name": "GROUPBY"
        },
        {
          "locale": "zh-TW",
          "name": "GROUPBY"
        }
      ],
      "signature": {
        "display": "GROUPBY(row_fields, values, function, [field_headers], [total_depth], [sort_order], [filter_array], [field_relationship])",
        "parameters": [
          {
            "description": "Grouping keys used to partition the input rows.",
            "name": "row_fields",
            "optional": false,
            "repeats": false
          },
          {
            "description": "Value vector or matrix aggregated within each group.",
            "name": "values",
            "optional": false,
            "repeats": false
          },
          {
            "description": "Current parked baseline supports the admitted grouped-aggregation callable/aggregate slice.",
            "name": "function",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "field_headers",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "total_depth",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "sort_order",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "filter_array",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "field_relationship",
            "optional": true,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "GROUPBY",
      "version_marker": null,
      "xlcall": null
    },
    "microsoft": "https://support.microsoft.com/en-us/office/groupby-function-5e08ae8c-6800-4b72-b623-c41773611505"
  },
  "try_it": {
    "formula": "=GROUPBY(B2:B5,C2:C5,LAMBDA(v,SUM(v)),0,0)",
    "inputs": {
      "B2": "east",
      "B3": "west",
      "B4": "east",
      "B5": "west",
      "C2": 3,
      "C3": 5,
      "C4": 7,
      "C5": 11
    }
  },
  "url": "https://handbook.dnacalc.com/functions/GROUPBY.html",
  "variants": [],
  "versions": [
    {
      "behaviour": "Implementation comments retain 60 COM grouping calls on 30 October 2026, including case-insensitive text keys, header modes, callable results and total ordering. This is one-build scope, with no earlier-build comparison.",
      "excel_build": "16.0 build 20527",
      "platform": "Windows through COM; bitness and CPU not stated in these comments",
      "sources": [
        "https://github.com/DnaCalc/DnaCalc/blob/da3ecc4fb19a3a5529708c311d0e8f05688ac165/crates/calc-func/src/catalogue/grouping.rs"
      ]
    }
  ]
}