data-arrganizer
v0.1.0
Published
The `Arrganizer` class is a utility for organizing, transforming, and formatting data sets. It provides various methods to group, filter, modify, and format data, as well as to manage the history of operations performed on the data.
Maintainers
Readme
Why Arrganizer?
Arrganizer is a zero-dependency TypeScript library that makes working with arrays of objects feel like working with a spreadsheet. If you've ever written long chains of .filter().map().reduce() just to organize your data, Arrganizer is for you.
What makes it different?
- Fluent API — Chain operations like
.groupByKey("city").sortByKey("revenue").take(10). Readable, composable, and concise. - Full history — Every operation is recorded. Undo/redo with a single call. No more lost states.
- Built-in formatting — Locale-aware number, date, currency formatting via
Intl. No external dependencies. - Type-safe — Full TypeScript support with generics. Your IDE knows your column names.
- Spreadsheet-like summaries — Get totals, averages, min/max with
getTables({total: true, average: true}). - Zero dependencies — Pure TypeScript. No bloat. 11KB gzipped.
- Works everywhere — Node.js, browsers, Deno. ESM & CJS builds included.
When to use Arrganizer
| Scenario | Arrganizer |
|----------|------------|
| You have an array of objects and need to group, filter, sort, or aggregate it | ✅ Perfect |
| You need undo/redo on data transformations | ✅ Built-in |
| You want formatted table output (console, HTML, CSV) | ✅ getTables() |
| You're building a data dashboard or reporting tool | ✅ Ideal |
| You need complex SQL-like joins, pivots, and aggregations | ✅ Supported |
| You're processing huge datasets (millions of rows) | ⚠️ Consider streaming |
Table of Contents
- Installation
- Quick Start
- Constructor
- Data Operations
- Column Operations
- Grouping & Filtering
- Transformation
- Aggregation
- Pagination
- Advanced Operations
- State Management
- Formatters
- Changelog
Installation
npm i data-arrganizerimport { Arrganizer } from 'data-arrganizer';Quick Start
import { Arrganizer } from 'data-arrganizer';
const sales = [
{ product: "Laptop", region: "EU", revenue: 1200 },
{ product: "Phone", region: "EU", revenue: 800 },
{ product: "Laptop", region: "US", revenue: 1500 },
{ product: "Phone", region: "US", revenue: 950 },
{ product: "Tablet", region: "EU", revenue: 600 },
{ product: "Tablet", region: "US", revenue: 700 },
];
const a = new Arrganizer(sales);
// Group by region, sort by revenue, show top 3
const result = a
.groupByKey("region")
.sortByKey("revenue", "desc")
.take(3)
.getTables({ total: true });
console.log(result);Constructor
new Arrganizer(data: DataRow[], options?: ArrganizerOptions)Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| historySize | number | 10 | Max undo/redo history depth |
| headerDictionary | Record<string, string> | - | Maps keys to display-friendly names |
| cellFormats | Record<string, string \| Function> | - | Per-column formatting rules |
| locale | string | "en" | Locale for formatting |
| decimals | number | 3 | Decimal places for numbers |
Cell Format Types
"number", "date", "time", "datetime", "eur", "usd", "huf", or a custom function.
const a = new Arrganizer(data, {
headerDictionary: { name: "Full Name", salary: "Annual Salary" },
cellFormats: { salary: "usd", joined: "date" },
locale: "en-US",
});Data Operations
getTables
Returns formatted tables with optional summary rows.
const tables = a.getTables({ total: true, average: true, min: true });
// Returns: TableData[] with title, summary, and table (header + body)getData
Returns the current internal state as DataSet[].
const datasets = a.getData();
console.log(datasets[0].data); // Array of rows
console.log(datasets[0].summary); // { total, min, max, average, length }getOriginalData
Returns the raw data passed to the constructor.
const original = a.getOriginalData();getHistory
Returns the full undo/redo history stack.
const history = a.getHistory();
console.log(history.length); // Number of states storedColumn Operations
addKey
Adds a new computed column.
a.addKey("revenueWithTax", (row) => (row.revenue as number) * 1.27);
// Adds a "revenueWithTax" column to every rowrenameKey
Renames a column.
a.renameKey("name", "fullName");
// "name" column is now called "fullName"removeKey
Removes a single column.
a.removeKey("age");removeKeys
Removes multiple columns.
a.removeKeys(["age", "salary", "department"]);keepKeys
Keeps only specified columns, removes everything else.
a.keepKeys(["name", "revenue"]);mergeColumns
Merges two columns using a custom function.
a.mergeColumns("firstName", "lastName", (first, last) => `${first} ${last}`, "fullName");
// "firstName" and "lastName" are replaced by "fullName"reorderColumns
Reorders columns. If addMissing is true (default), unlisted columns are appended.
a.reorderColumns(["revenue", "product", "region"]);
a.reorderColumns(["revenue", "product"], false); // Only these two columnsGrouping & Filtering
groupByKey
Groups data by a single key into separate datasets.
a.groupByKey("region");
// Creates separate datasets for each unique regiongroupByKeys
Groups by multiple keys (cross-product).
a.groupByKeys(["region", "product"]);
// Creates datasets for each region+product combinationgroupByDate
Groups by date at a specified granularity.
a.groupByDate("MONTH", "orderDate");
// TimeRange: "YEAR" | "MONTH" | "WEEK" | "DAY" | "HOUR" | "MINUTE" | "SECOND"filterByKey
Filters rows where the key matches any of the given values.
a.filterByKey("region", ["EU", "APAC"]);contains
Filters rows where ANY column contains the given substring (case-insensitive).
a.contains("laptop");where
Filters rows with a condition operator.
a.where("revenue", ">", 1000);
a.where("status", "===", "active");
a.where("name", "contains", "john");
// Operators: ">", "<", ">=", "<=", "===", "!==", "contains"distinct
Returns unique values for a column (read-only, no mutation).
const regions = a.distinct("region");
// ["EU", "US", "APAC"]Transformation
modifyValue
Transforms values in a specific column.
a.modifyValue("revenue", (val) => (val as number) * 1.1);mapRows
Transforms every row with a custom function.
a.mapRows((row) => ({
...row,
label: `${row.product} (${row.region})`,
revenue: (row.revenue as number) * 1.1,
}));sortByKey
Sorts by a key in ascending or descending order.
a.sortByKey("revenue", "desc");Aggregation
count
Returns total row count across all datasets.
const total = a.count();sum
Returns the sum of numeric values for a column.
const totalRevenue = a.sum("revenue");mean
Returns the arithmetic mean for a column.
const avgRevenue = a.mean("revenue");frequencyByKeysValue
Groups by keys and counts frequency. Optionally aggregates numeric columns.
a.frequencyByKeysValue(["region"]);
// Adds a "frequency" column with the count of each region
a.frequencyByKeysValue(["region"], "count", ["revenue"]);
// "count" column = frequency, "revenue" = sum of revenues per regionPagination
take
Keeps only the first n rows per dataset.
a.take(10);skip
Skips the first n rows per dataset.
a.skip(5);head
Alias for take. Returns first n rows (default: 1).
a.head(5);tail
Returns the last n rows per dataset (default: 1).
a.tail(5);sample
Returns n random rows per dataset.
a.sample(3);Advanced Operations
pivot
Transforms long-format data to wide-format.
const data = [
{ id: 1, metric: "revenue", value: 100 },
{ id: 1, metric: "cost", value: 50 },
{ id: 2, metric: "revenue", value: 200 },
{ id: 2, metric: "cost", value: 80 },
];
new Arrganizer(data).pivot("id", "metric", "value");
// Result:
// [{ id: 1, revenue: 100, cost: 50 },
// { id: 2, revenue: 200, cost: 80 }]join
Left-joins this dataset with another Arrganizer on a shared key.
const a = new Arrganizer([{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]);
const b = new Arrganizer([{ id: 1, score: 95 }, { id: 2, score: 87 }]);
a.join(b, "id");
// [{ id: 1, name: "Alice", score: 95 },
// { id: 2, name: "Bob", score: 87 }]pipe
Composes operations through a pipeline of functions.
const process = (a) => a.groupByKey("region").sortByKey("revenue", "desc");
a.pipe(process, (a) => a.take(5));diff
Compares two Arrganizer states and returns added, removed, and unchanged rows.
const a = new Arrganizer([{ id: 1 }, { id: 2 }, { id: 3 }]);
const b = new Arrganizer([{ id: 2 }, { id: 3 }, { id: 4 }]);
const { added, removed, unchanged } = a.diff(b);
// added: [{ id: 4 }]
// removed: [{ id: 1 }]
// unchanged: [{ id: 2 }, { id: 3 }]State Management
clone / snapshot
Creates an independent deep copy of the current state.
const backup = a.clone();
a.take(3);
console.log(backup.getData()[0].data.length); // Still has all rowstoJSON / fromJSON
Serializes and deserializes the Arrganizer state.
const json = a.toJSON();
const restored = new Arrganizer([{ id: 0 }]).fromJSON(json);reset
Resets to the original data and clears history.
a.groupByKey("region");
a.reset(); // Back to original dataundo / redo
Steps backward/forward through the operation history.
a.groupByKey("region"); // State 1
a.sortByKey("revenue"); // State 2
a.undo(); // Back to State 1
a.redo(); // Forward to State 2Formatters
Arrganizer exports its formatters for standalone use:
import {
formatNumbers,
formatDate,
formatTime,
formatDateTime,
getMonthName,
getDayName,
isValidLocale,
} from 'data-arrganizer';
formatNumbers(1234.56, { locale: "de-DE", currency: "EUR" }); // "1.234,56 €"
formatDate("2024-01-15", { locale: "hu-HU" }); // "2024. 01. 15."
getMonthName(new Date(2024, 0), "hu"); // "január"
getDayName(new Date(2024, 0, 15), "hu", false); // "hétfő"Changelog
v0.0.3
New Features
addKey,renameKey— column operationsdistinct,where— advanced queryingtake,skip,head,tail,sample— paginationmapRows— general row transformationcount,sum,mean— quick aggregationsclone,snapshot,toJSON,fromJSON— state managementpivot,join,pipe,diff— advanced operationsSECONDtime range forgroupByDate
Bug Fixes
- Fixed
uniqueKeysalways returning true - Fixed history storing references instead of deep copies
- Fixed
mergeColumns/reorderColumnsmissing undo support - Fixed
sortByKeyclosure variable bug - Fixed
formatDataSetscrash on empty data
Code Quality
- Removed unused types (
ArrganizerType,ArrganizerConstructor,FormattersType) - Exported formatter functions for standalone use
- All pre-existing lint and test issues resolved
License
MIT
