Schematiq.Collections
1.0.0-beta.1
dotnet add package Schematiq.Collections --version 1.0.0-beta.1
NuGet\Install-Package Schematiq.Collections -Version 1.0.0-beta.1
<PackageReference Include="Schematiq.Collections" Version="1.0.0-beta.1" />
<PackageVersion Include="Schematiq.Collections" Version="1.0.0-beta.1" />
<PackageReference Include="Schematiq.Collections" />
paket add Schematiq.Collections --version 1.0.0-beta.1
#r "nuget: Schematiq.Collections, 1.0.0-beta.1"
#:package Schematiq.Collections@1.0.0-beta.1
#addin nuget:?package=Schematiq.Collections&version=1.0.0-beta.1&prerelease
#tool nuget:?package=Schematiq.Collections&version=1.0.0-beta.1&prerelease
Schematiq.Collections
Fast, light immutable collections for .NET: lists, sets, dictionaries, JSON-like objects and column-store tables, with a compact binary serializer for all of them.
Every edit returns a new collection and leaves the original unchanged, sharing most of its structure, so keeping old versions is cheap. The library targets .NET Standard 2.0 and .NET 8, with nullable annotations.
dotnet add package Schematiq.Collections
Collections
| Type | What it is |
|---|---|
ISchematiqList<T> |
A list with cheap edits at either end and by position, plus Subset, Reverse and Concat. |
ISchematiqHashSet<T> |
An unordered set. |
ISchematiqOrderedHashSet<T> |
A set that keeps insertion order and can be indexed by position. |
ISchematiqDictionary<TKey, TValue> |
An unordered dictionary. |
ISchematiqOrderedDictionary<TKey, TValue> |
A dictionary that keeps insertion order, with access by position. |
SchematiqObject |
An ordered dictionary of text keys to values of any kind, like a JSON object. |
ISchematiqTable |
A table of named, typed, nullable columns. |
Each is created through a static class of the same name without the I, such as SchematiqList.Create, and
implements the matching read-only .NET interface (IReadOnlyList<T>, IReadOnlyDictionary<TKey, TValue> and so on).
using Schematiq.Collections;
ISchematiqList<int> list = SchematiqList.Create(1, 2, 3);
var longer = list.Push(4).PushFront(0); // 0, 1, 2, 3, 4; list is still 1, 2, 3
var squares = SchematiqList.View(1000, i => i * i); // computed as read, costs nothing to make
var prices = SchematiqDictionary.Empty<string, decimal>()
.Add("apple", 0.40m)
.Add("pear", 0.55m);
var cheaper = prices.SetItem("pear", 0.50m);
var steps = SchematiqOrderedDictionary.Empty<string, int>()
.Add("first", 1)
.Add("third", 3)
.AddBefore("third", "second", 2); // first, second, third
var person = SchematiqObject.Create(("name", "Ada"), ("born", 1815));
Console.WriteLine(person); // {"name": "Ada", "born": 1815}
Sets and dictionaries of up to 8 entries are stored as plain arrays, and lists of up to 4 elements inline, so small
collections are small. Compact rebuilds any collection in its smallest form.
Large collections that are mostly read
Pass SchematiqHashLayout.ReadMostly to CreateRange on any of the hashed collections to build larger leaves. A large
set of integers then keeps about 25% less memory, and a dictionary about 19% less, with lookups and enumeration no
slower. The first edits to each part of such a collection cost more, after which edits cost the usual.
var ids = SchematiqHashSet.CreateRange(Enumerable.Range(0, 1_000_000), null, SchematiqHashLayout.ReadMostly);
Tables
ISchematiqTable is an immutable column-store table, with relational operators over expressions that follow SQL's
rules for nulls.
using Schematiq.Collections;
using Schematiq.Collections.Tables.Expressions;
var sales = SchematiqTable.Create(
SchematiqColumn.Create("Region", ["North", "South", "North", "East"]),
SchematiqColumn.Create("Sales", [120.0, 80.0, 45.0, 200.0]));
var totals = sales
.Filter(Expr.Col("Sales") > 50)
.Group("Region")
.Aggregate(Expr.Sum(Expr.Col("Sales")).As("Total"), Expr.Count().As("Orders"))
.Sort(Expr.Col("Total").Descending());
foreach (var row in totals.Rows)
{
Console.WriteLine(row.ToObject()); // {"Region": "East", "Total": 200, "Orders": 1} ...
}
Tables also support Calculate, Project, Rename, Distinct, Skip and Take; inner, outer, semi, anti,
condition and cross joins; Union, Intersect and Except; Pivot and Unpivot; row edits and Append; and hash
and sorted indexes, including a primary key. SchematiqTable.FromObjects makes a table over a list of your own objects.
Serialization
SchematiqSerializer writes any of these collections, and the values in them, to a compact binary format and reads
them back equal. Repeated text is written once, tables column by column, and a collection used more than once is
written once and read back shared.
using Schematiq.Collections.Serialization;
var serializer = SchematiqSerializer.Default;
byte[] bytes = serializer.SerializeToBytes(sales);
ISchematiqTable copy = serializer.Deserialize<ISchematiqTable>(bytes);
Use SchematiqSerializerOptions for Deflate or Brotli compression (Brotli needs the .NET 8 build), and to register a
SchematiqCodec<T> for each of your own types. Files identify codecs by an id you choose, never by a .NET type name,
and reading checks counts, lengths and nesting against limits, so damaged or hostile data throws
SchematiqSerializationException rather than exhausting memory.
Licence
MIT.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.6.3)
-
net8.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Schematiq.Collections:
| Package | Downloads |
|---|---|
|
OcctNet.Foundation
OCCT.NET foundation: a managed port of OCCT's Standard, Precision and maths packages (gp, ...). |
|
|
Build123d
A .NET port of build123d, a code-first CAD library built on OpenCascade. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-beta.1 | 152 | 11/2/2026 |
| 0.1.0 | 1,803 | 9/28/2017 |
Changes since 0.3.0.
New collections:
- SchematiqHashSet: an unordered set.
- SchematiqOrderedHashSet: a set that keeps insertion order and can be indexed by position.
- SchematiqDictionary: an unordered dictionary.
- SchematiqOrderedDictionary: a dictionary that keeps insertion order, with access by position.
- SchematiqObject: an ordered dictionary of text keys, compared exactly, to values of any kind, like a JSON object. Edits return SchematiqObject, equality compares contents in any order, and ToString writes JSON. ISchematiqObject is its interface, which views implement too.
All four create and enumerate quickly, and make runs of single edits cheap. Each ordered interface extends its unordered one.
Ordered sets and dictionaries:
- Insert, AddBefore, AddAfter, RemoveAt, Move, MoveBefore and MoveAfter. A collection that never inserts before its end keeps its size and speed.
Read-mostly layout:
- CreateRange on all four hashed collections takes an optional SchematiqHashLayout. ReadMostly builds 256-entry hash leaves instead of 32-entry ones: a large set of integers keeps 25% less memory, and a dictionary of integers 19% less, with lookups and enumeration no slower. The first edits to each part of such a collection take up to twice as long and allocate up to three times as much, after which edits cost the usual.
Small collections:
- Sets and dictionaries of up to 8 entries are stored as plain arrays, and lists of 1 to 4 elements inline, so they are smaller and faster to create.
- Every collection has Compact, which rebuilds it in its smallest form.
SchematiqTable (preview):
- An immutable column-store table of named, typed, nullable columns, with rows readable as views.
- Expressions over columns, with SQL null logic: Filter, Calculate, Project, Rename, Sort, Distinct, Skip and Take.
- Pivot, with totals, ordering, a fill for empty combinations and named generated columns; and Unpivot, which keeps the columns' type where it can.
- Grouped and whole-table aggregates; inner, outer, semi, anti, condition and cross joins; Union, Intersect and Except.
- Row edits and Append; hash and sorted indexes, optionally unique, and a primary key that keeps the rows in order.
- Column and index names are compared exactly, case and all, as JSON compares an object's keys.
- TableRow.ToObject returns the row as an ISchematiqObject that reads the table in place.
- SchematiqTable.FromObjects makes a table over a list of your own objects, a column per property or chosen with ObjectColumn.
- SchematiqTableBase lets other kinds of table use every operator.
SchematiqList:
- SchematiqList.View returns a read-only list converted from another list, or computed from positions, as it is read: making one, Subset and Reverse cost nothing, and an edit copies it first.
- Create lists from spans and collection expressions.
- Faster indexing and enumeration, and cheaper SetItem, Insert and RemoveAt.
- Fixed Reverse after multi-item edits and after edits to double sequences, Subset of stems with part-filled leaves, and negative run lengths, which now throw ArgumentOutOfRangeException.
Serialization:
- SchematiqSerializer writes lists, sets and dictionaries (ordered ones in their order), Objects and tables to a compact binary format, and reads them back equal: tables with their schema, nulls, primary key and indexes (built again when read). Elements may be primitives, other Schematiq collections, or your own types through codecs (SchematiqCodec of T) registered by an id the file records, never a .NET type name.
- Repeated text is written once and referred to after; tables column by column with null flags; whole numbers, and numbers of up to six decimal places, as integers; dates of whole days or seconds as the change from the one before. A collection used more than once is written once and read back shared.
- Optional Deflate compression, or Brotli on .NET (not in the .NET Standard 2.0 build).
- Reading checks counts, lengths and nesting against limits in SchematiqSerializerOptions, and sets memory aside only as data arrives: damaged or hostile data throws SchematiqSerializationException.
Packaging:
- Targets netstandard2.0 and net8.0, with nullable annotations.
- The assembly is no longer strong-name signed.