{"id":19011912,"url":"https://github.com/3squared/peakpivot","last_synced_at":"2025-10-30T13:11:18.243Z","repository":{"id":68491607,"uuid":"323874697","full_name":"3Squared/PeakPivot","owner":"3Squared","description":"Build a pivot table using Swift and a CSV.","archived":false,"fork":false,"pushed_at":"2021-04-30T08:45:00.000Z","size":5982,"stargazers_count":0,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-01T21:47:10.126Z","etag":null,"topics":["csv","excel","peak-framework","pivot-tables","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/3Squared.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-23T10:42:39.000Z","updated_at":"2021-05-09T15:34:15.000Z","dependencies_parsed_at":null,"dependency_job_id":"a40ee455-446f-4846-9997-e27a9d332145","html_url":"https://github.com/3Squared/PeakPivot","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3Squared%2FPeakPivot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3Squared%2FPeakPivot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3Squared%2FPeakPivot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/3Squared%2FPeakPivot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/3Squared","download_url":"https://codeload.github.com/3Squared/PeakPivot/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240043107,"owners_count":19739019,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csv","excel","peak-framework","pivot-tables","swift"],"created_at":"2024-11-08T19:16:06.429Z","updated_at":"2025-10-30T13:11:13.219Z","avatar_url":"https://github.com/3Squared.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PeakPivot\n\n[![Swift](https://github.com/3Squared/PeakPivot/actions/workflows/swift.yml/badge.svg)](https://github.com/3Squared/PeakPivot/actions/workflows/swift.yml)\n\n\u003c!-- ![Swift](https://github.com/3squared/PeakPivot/workflows/Swift/badge.svg?branch=main) ---\u003e\n\n[Wikipedia](https://en.wikipedia.org/wiki/Pivot_table) says:\n\n\u003e Pivot tables are a technique in data processing. They arrange and rearrange (or \"pivot\") statistics in order to draw attention to useful information. This leads to finding figures and facts quickly making them integral to data analysis. \n\nPeakPivot is a pure-swift implementation of pivot tables modelled on the implementation offered by Microsoft Excel and Google Sheets. PeakPivot provides the base types and business logic for summarising tabular data into a pivot table.\n\n## Types \n\nPeakPivot defines a number of types that model\n\n1. The **input** data necessary for building a pivot table,\n2. The **configuration** values for a pivot table builder, \n3. The resulting **output** pivot table.\n\nBelow is screenshot of a pivot table built in Microsoft Excel from the [`people.csv`](Assets/people.csv) file. It is annotated to show the corresponding PeakPivot types.\n\n![](Assets/diagram.png)\n\n### 1. Input \n\nThese types are the input to the pivot building logic. They are highlighted in blue in the [diagram above](#Types).\n\n`Table`. A array of `TableRow`s. This is the input to data to be pivotted. For example this may come from a CSV file.\n\n`TableRow`. A key-value pair of `[FieldName : FieldValue]`. This represents a single row in a table. If using a CSV the `FieldName` corresponds to the column-name, and the `FieldValue` corresponds to the column-value for that row.\n\n`FieldName`. A string representing a column-name in the input table.\n\n`FieldValue`. A string representing a cell-value for a given column and row. Note that `String` is used as the type here to make it easier for CSV parsing and conforming `FieldValue` to `Equatable` (necessary for unit testing). Any non-string value can be boxed into a `FieldValue` if required.\n\n### 2. Builder Configuration\n\nThese types configure the pivot that is built. They are highlighted in green in the [diagram above](#Types).\n\n`BuildPivot`. A protocol defining the business logic for building a pivot from a supplied `Table` and array of `FieldName`s to pivot around. A protocol extension provides a default implementation of the `build()` function. Either conform a type to `BuildPivot` or use the provided concrete implementation `PivotBuilder`.\n\n`PivotBuilder`. A concrete implementation of the `BuildPivot` protocol that provides defaults for the configuration varaibles.\n\n`FieldName`. A string representing a column-name from the input table to pivot around.\n\n`BuildPivotFilter`. Describes how to apply a filter to a pivot table to exclude certain `FieldName`s and values.\n\n`BuildPivotDescriptor`. Describes how to apply a sort to pivot table.\n\n### 3. Output\n\nThese types are the output from the pivot building logic. They are highlighted in red in the [diagram above](#Types).\n\n`Pivot`. A pivot table, generated by processing a `Table` using a `BuildPivot`. Defines the `PivotRow`s in the output table, the `FilterField`s that can be used for subsequent filting, and the total number of rows in the table.\n\n`PivotRow`. A row in a pivot table, that stores the computed value information (the count, sum, percentage etc), what level in the overall table is sits at, it's title (corresponds to the `FieldName` in the input `Table`), and any subrows it has. The subrows represent the nesting of groups in a pivot table. The number of levels to this nesting is equal to  (number of `FieldName`s - 1) as passed into the `BuildPivot`.\n\n`FilterField`. All the fields from a generated pivot table that can be used to filter the pivot table on a subsequent build. Use these `FilterField`s to create `BuildPivotFilter`s as needed.\n\n## Building a Pivot\n\nTo recreate the pivot table shown in the [Excel spreadsheet above](#Types) we load in the [`people.csv`](Assets/people.csv) csv file using SwiftCSV (including with PeakPivot) and construct a `PivotBuilder` with the corresponding input and configuration data.\n\nSet the `fields` variable to the `FieldName`s you want to group the pivot table using. The last `FieldName` in the array defines the `FieldValue`s in the input `Table` to summarise using sum, count and percentage operators.\n\nOnce configured call the `build()` function.\n\n```swift\ndo {\n    let csvURL = URL(fileURLWithPath: \"url/to/people.csv\")\n    let csv = try CSV(url: csvURL)\n    let csvRows = csv.namedRows\n\n    let builder = PivotBuilder()\n    \n    // Set the input\n    builder.table = csvRows\n    builder.fields = [\"title\", \"age\"] // \"age\" is summarised\n    \n    // Configure the builder\n    builder.sortDescriptor = .byTitle(ascending: false) \n    builder.filters = [BuildPivotFilter(fieldName: \"title\", exclude: [\"Blank\", \"Rev\"])] // exclude \"Blank\" and \"Rev\" from the pivot table\n    builder.sumsEnabled = true // compute sums\n    builder.percentagesEnabled = true // compute percentages\n\n    // Run the builder\n    let pivot = try builder.build()\n    \n    // Below are examples of the output \n    // pivot.rows will equal\n    let pivotRows = [\n    PivotRow(level: 0, title: \"Ms\", value: PivotRow.Value(count: 1, sum: 33, percentage: 1/9), subRows: [\n        PivotRow(level: 1, title: \"33\", value: PivotRow.Value(count: 1, sum: 33, percentage: 1/9), subRows: nil),\n    ]),\n    PivotRow(level: 0, title: \"Mrs\", value: PivotRow.Value(count: 1, sum: 45, percentage: 1/9), subRows: [\n        PivotRow(level: 1, title: \"45\", value: PivotRow.Value(count: 1, sum: 45, percentage: 1/9), subRows: nil),\n    ]),\n    PivotRow(level: 0, title: \"Mr\", value: PivotRow.Value(count: 2, sum: 75, percentage: 2/9), subRows: [\n        PivotRow(level: 1, title: \"54\", value: PivotRow.Value(count: 1, sum: 54, percentage: 1/9), subRows: nil),\n        PivotRow(level: 1, title: \"21\", value: PivotRow.Value(count: 1, sum: 21, percentage: 1/9), subRows: nil),\n    ]),\n    PivotRow(level: 0, title: \"Honorable\", value: PivotRow.Value(count: 2, sum: 83, percentage: 2/9), subRows: [\n        PivotRow(level: 1, title: \"54\", value: PivotRow.Value(count: 1, sum: 54, percentage: 1/9), subRows: nil),\n        PivotRow(level: 1, title: \"29\", value: PivotRow.Value(count: 1, sum: 29, percentage: 1/9), subRows: nil),\n    ]),\n    PivotRow(level: 0, title: \"Dr\", value: PivotRow.Value(count: 3, sum: 143, percentage: 3/9), subRows: [\n        PivotRow(level: 1, title: \"63\", value: PivotRow.Value(count: 1, sum: 63, percentage: 1/9), subRows: nil),\n        PivotRow(level: 1, title: \"42\", value: PivotRow.Value(count: 1, sum: 42, percentage: 1/9), subRows: nil),\n        PivotRow(level: 1, title: \"38\", value: PivotRow.Value(count: 1, sum: 38, percentage: 1/9), subRows: nil),\n    ])\n\n    // pivot.total will equal\n    let pivotTotal = 9\n\n    // pivot.fieldFields will equal\n    let filterFields = [\n        FilterField(name: \"title\", values: [\n            \"Dr\",\n            \"Honorable\",\n            \"Mr\",\n            \"Mrs\",\n            \"Ms\",\n            \"Rev\",\n            Blank\n        ]),\n        FilterField(name: \"age\", values: [\n            \"21\",\n            \"25\",\n            \"29\",\n            \"33\",\n            \"35\",\n            \"36\",\n            \"38\",\n            \"40\",\n            \"41\",\n            \"42\",\n            \"44\",\n            \"45\",\n            \"52\",\n            \"54\",\n            \"57\",\n            \"58\",\n            \"63\",\n            \"68\"\n        ])\n    ]\n\n]\n\n} catch  {\n    // Handle errors\n}\n\n```\n\nFor more examples of how to use PeakPivot see the [unit tests](Tests/PeakPivotTests). There is also a basic [example iOS project](Example) that uses PeakPivot.\n\n## Installation\n\nPeakPivot supports the Swift Package Manager. Add the PeakPivot dependency in your `package.swift`.\n\n```swift\ndependencies: [\n    .package(\n        url: \"https://github.com/3squared/PeakPivot.git\",\n        .upToMajor(from: \"2.0.0\")\n    ),\n]\n```\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details\n\n## Acknowledgments\n\n* [SwiftCSV](https://github.com/swiftcsv/SwiftCSV)\n\n# Peak Framework\n\nThe Peak Framework is a collection of open-source microframeworks created by the team at [3Squared](https://github.com/3squared), named for the [Peak District](https://en.wikipedia.org/wiki/Peak_District). It is made up of:\n\n|Name|Description|\n|:--|:--|\n|[PeakOperation](https://github.com/3squared/PeakOperation)|Provides enhancement and conveniences to `Operation`, making use of the `Result` type.|\n|[PeakNetwork](https://github.com/3squared/PeakNetwork)|A networking framework built on top of `Session` using PeakOperation, leveraging the power of `Codable`.|\n|[PeakCoreData](https://github.com/3squared/PeakCoreData)|Provides enhances and conveniences to `Core Data`.|\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F3squared%2Fpeakpivot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F3squared%2Fpeakpivot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F3squared%2Fpeakpivot/lists"}