Skip to content

Structured Data

Paul Köhler edited this page Jan 23, 2026 · 10 revisions

Introduced in version 3.1, CmpStr provides built-in support for structured data comparisons. This allows arrays of arbitrary objects to be compared using one of their properties, while preserving full access to the original objects in the result set.

Structured data processing is implemented internally by the StructuredData utility class, exported by cmpstr/root. It acts as a thin orchestration layer between object extraction, string comparison, and result reconstruction.

This page explains how structured data comparisons are implemented internally, how results are normalized and rebuilt, and how this integrates with CmpStr’s comparison modes.

Core Concept

Structured data processing in CmpStr follows a three-step pipeline:

  1. Extraction – Convert object properties into plain string arrays
  2. Comparison – Delegate string comparison to existing CmpStr batch or pairwise functions
  3. Reconstruction – Reattach original objects and metadata to results

At no point are comparison algorithms duplicated or modified.
Structured data support is strictly an adapter layer on top of the existing comparison engine.

StructuredData Factory

Internally, structured processing is handled by the generic class:

StructuredData< T = any, R = MetricRaw >

Instances are created via the factory method:

StructuredData.create( data, key )

Where:

  • data is an array of arbitrary objects
  • key is the property used for string extraction and comparison
  • T represents the object type
  • R represents the raw metric result type (if exposed)

The instance stores only references to the original data and key.
No preprocessing or copying is performed at construction time.

Property Extraction

Before any comparison takes place, object properties are extracted into string arrays.

Extraction Rules:

  • Values are read using the configured property key
  • Strings are passed through unchanged
  • Non-string values are coerced via String( value )
  • null and undefined are converted to empty strings

Extraction is implemented via:

  • extract() for the primary dataset
  • extractFrom() for secondary or foreign datasets

To reduce allocation overhead, extracted arrays are obtained from a shared array pool and released immediately after use.

Delegation to Comparison Functions

Once extracted, comparisons are performed by calling existing CmpStr functions supplied by the public API layer.

Structured data processing itself does not:

  • Select metrics
  • Control comparison modes
  • Modify similarity behavior

Instead, it delegates fully to one of the following patterns:

Batch Lookups

fn ( query, extractedStrings, options )

Used by:

  • structuredLookup()
  • structuredMatch()
  • structuredClosest()
  • structuredFurthest()

This corresponds to batch comparison mode.

Pairwise Lookups

fn ( aStrings, bStrings, options )

Used by:

  • structuredPairs()

This corresponds to pairwise comparison mode and requires both arrays to be of equal length.

Example

import { CmpStr } from 'cmpstr';

const cmp = CmpStr.create( { metric: 'levenshtein' } );
const res = cmp.structuredLookup( 'Mayer', [
  { id: '1', name: 'Meyer' }, { id: '2', name: 'Miller' },
  { id: '3', name: 'Müller' }, { id: '4', name: 'Meier' }
], 'name' );

Try yourself at OneCompiler

Result Normalization

Because different comparison functions may return different result formats, all results are first normalized into a common internal structure.

Supported Input Formats:

  • MetricResultSingle[]
  • CmpStrResult[]

During normalization:

  • Results are converted into a unified { a, b, res, raw } shape
  • An internal index (__idx) is attached to preserve positional information
  • Unsupported result formats trigger a TypeError

This step ensures consistent downstream processing regardless of the comparison function used.

Sorting and Filtering

After normalization, results may be optionally:

  • Sorted by similarity score (asc or desc)
  • Filtered to remove zero-similarity matches

Sorting behavior is controlled via StructuredDataOptions.sort.

Filtering of zero-matches is controlled via StructuredDataOptions.removeZero.

Both operations are applied before objects are reattached.

Result Reconstruction

The final step rebuilds results by mapping comparison outputs back to their original objects.

Mapping Strategy:

  • A lookup table maps extracted string values to their original object indices
  • Duplicate values are handled deterministically using occurrence tracking
  • If a string cannot be mapped, the original comparison index is used as fallback

This ensures stable and predictable object mapping even when:

  • Results are sorted
  • Results are filtered
  • Only subsets (e.g. closest/furthest) are returned

Output Formats

Structured data processing supports two output modes:

Full Result Mode (default)

Each result includes:

  • The original object
  • The key used for comparison
  • The comparison result (source, target, match)
  • Optional raw metric data

Objects-Only Mode

If objectsOnly is enabled:

  • Only the matched original objects are returned
  • All comparison metadata is omitted

This is useful for minimal lookup scenarios where only matching objects matter.

Notes

  • Structured data support is fully generic and type-safe
  • No assumptions are made about object shape or semantics
  • Memory allocations are minimized using pooled arrays
  • Comparison logic remains entirely within the core CmpStr engine
  • Structured processing adds zero overhead when not used

For usage examples and function signatures, refer to the API Reference.

Clone this wiki locally