CKN Technology Core · Array Extensions

CKN Technology Core
Array Extensions

Custom utility extensions for Array<T> used across the CKN Framework. This page documents all helpers for debugging, querying, sets, paging, sorting, statistics and async workflows.

Import

To enable the custom Array<T> extensions, import the core module once at your application entry point. This registers all helpers on Array.prototype.

import "@ckn-technology/core";

All examples below assume this import has already been executed once at application startup.

1. Debug & Utility

print()

Description
Prints the array contents to the console (joined by comma) and returns the same array for chaining.

Signature

print(): Array<T>

Example

[1, 2, 3].print(); 
// console: "1,2,3"

const total = [1, 2, 3]
  .print()      // logs: 1,2,3
  .sum();       // 6

clone()

Description
Creates a shallow copy of the array using the spread operator. Useful to avoid mutating the original array.

Signature

clone(): Array<T>

Example

const a = [{ id: 1 }, { id: 2 }];
const b = a.clone();

b[0].id = 99;
console.log(a[0].id); // 99 (shallow copy)

const nums = [1, 2, 3];
const numsCopy = nums.clone(); // [1, 2, 3]

same(array)

Description
Checks whether two arrays have the same length and equal items using == (loose equality).

Signature

same(array: Array<T>): boolean

Example

[1, 2, 3].same([1, 2, 3]);   // true
[1, 2, 3].same([1, 2]);      // false
[1, 2, 3].same([1, 2, '3']); // true

toText(sp = ",", q = "")

Description
Converts array items to a single string, separated by sp and optionally wrapped with quote character q.

Signature

toText(sp?: string, q?: string): string

Example

[1, 2, 3].toText();                // "1,2,3"
['a', 'b'].toText('|');            // "a|b"
['a', 'b'].toText(',', '"');       // "\"a\",\"b\""

2. Query & Transform Helpers

select(selectFunc)

Maps each element through selectFunc and returns a new array (similar to Array.prototype.map).

Signature

select(selectFunc: (item: T) => any): any[]

Example

const nums = [1, 2, 3];
const squares = nums.select(x => x * x); 
// [1, 4, 9]

union(list)

Concatenates the current array with list, or flattens one level when list == null.

Signature

union(list: Array<T> | null): Array<T>

Example

// Concatenate
[1, 2].union([3, 4]);        
// [1, 2, 3, 4]

// Flatten one level when list is null
[[1, 2], [3, 4]].union(null); 
// [1, 2, 3, 4]

intersect(list)

Returns a new array containing elements that exist in both arrays (using indexOf). If list is null or empty, returns [].

Signature

intersect(list: Array<T> | null): Array<T>

Example

[1, 2, 3].intersect([2, 3, 4]); 
// [2, 3]

[1, 2].intersect(null);
// []

where(condition)

Wrapper around Array.prototype.filter with a more expressive, LINQ-like name for business rules.

Signature

where(condition: (item: T) => boolean): Array<T>

Example

const nums = [1, 2, 3, 4, 5];
const even = nums.where(x => x % 2 === 0);
// [2, 4]

count(condition?)

Counts elements in the array. Without arguments, returns length; with condition, counts only elements where the predicate returns true.

Signature

count(): number
count(condition: (item: T) => boolean): number

Example

[1, 2, 3].count();                   
// 3

[1, 2, 3, 4].count(x => x > 2);    
// 2

distinct(distinctFunc?)

Removes duplicates from the array.
Modes:

  • No argument: uses loose equality (==) to keep first occurrence of each value.
  • distinctFunc(item): treat return value as a key; duplicates share the same key.
  • distinctFunc(item, output): custom check; return true if already exists in output.

Signature

distinct(): any[]
distinct(distinctFunc: (item: any) => any): any[]
distinct(distinctFunc: (item: any, output: any[]) => boolean): any[]

Example

[1, 1, 2, 2, 3].distinct(); 
// [1, 2, 3]

const people = [
  { id: 1, name: 'A' },
  { id: 1, name: 'B' },
  { id: 2, name: 'C' }
];

// Distinct by key (id)
people.distinct(p => p.id);
// [
//   { id: 1, name: 'A' },
//   { id: 2, name: 'C' }
// ]

first(condition?) / last(condition?)

Returns the first / last element, or the first / last that matches a predicate. Special behavior:

  • No argument: first()this[0], last() ⇒ last item.
  • condition.length == 1: treat as predicate; return first/last item where condition(item) is true.
  • condition.length > 1: treat as projection; return first/last projected value.

Signature

first(): T
first(condition: (item: T) => boolean | number): any

last(): T
last(condition: (item: T) => boolean | number): any

Example

[1, 2, 3].first();      
// 1

[1, 2, 3, 4].last(x => x > 1); 
// 4

// Projection usage (less common)
[1, 2, 3].first(x => x * 10); 
// 10 (first projected)

repeat(n, isClone?)

Repeats the array n times and returns a new array. When isClone is true, each object is shallow-cloned ({ ...item }) to avoid shared references.

Signature

repeat(n: number, isClone?: boolean): Array<T>

Example

[1, 2].repeat(3); 
// [1, 2, 1, 2, 1, 2]

const objs = [{ id: 1 }];
const reps = objs.repeat(3, true);
// [{id:1}, {id:1}, {id:1}] (different object references)

group(...keys)

Groups an array of objects into a nested structure by one or more property names.
Each key level creates another object layer.

Signature

group(...keys: string[]): any

Example

const data = [
  { country: 'TH', city: 'BKK', value: 1 },
  { country: 'TH', city: 'BKK', value: 2 },
  { country: 'TH', city: 'CNX', value: 3 },
  { country: 'VN', city: 'HCM', value: 4 },
];

const grouped = data.group('country', 'city');
/*
{
  TH: {
    BKK: [ { ... }, { ... } ],
    CNX: [ { ... } ]
  },
  VN: {
    HCM: [ { ... } ]
  }
}
*/

unique(compareFunc?)

Similar to distinct, but uses a simpler interface:
By default, removes duplicates using loose equality (==). With compareFunc, you decide if an item already exists in the result.

Signature

unique(): Array<T>
unique(compareFunc: (item: T, list: Array<T>) => boolean): Array<T>

Example

[1, 1, 2, 2, 3].unique(); 
// [1, 2, 3]

const items = [
  { id: 1, name: 'A' },
  { id: 1, name: 'B' },
  { id: 2, name: 'C' }
];

const uniqueById = items.unique((item, list) =>
  list.some(x => x.id === item.id)
);
// [{ id: 1, name: 'A' }, { id: 2, name: 'C' }]

flatten()

Flattens a 2D array (T[][]) into a 1D array (T[]) one level deep.

Signature

flatten(): Array<any>

Example

const nested = [[1, 2], [3, 4], [5]];
nested.flatten(); 
// [1, 2, 3, 4, 5]

indexBy(keySelector)

Builds an object (dictionary) from the array, keyed by keySelector(item). Later lookups become O(1) for that key.

Signature

indexBy(
  keySelector: (item: T) => string | number
): Record<string | number, T>

Example

const users = [
  { id: 1, name: 'A' },
  { id: 2, name: 'B' }
];

const byId = users.indexBy(u => u.id);
/*
{
  1: { id:1, name:'A' },
  2: { id:2, name:'B' }
}
*/

toMap(keySelector, valueSelector)

Converts the array into a Map<K, V> using keySelector for keys and valueSelector for values.

Signature

toMap<K, V>(
  keySelector: (item: T) => K,
  valueSelector: (item: T) => V
): Map<K, V>

Example

const products = [
  { id: 'A', price: 10 },
  { id: 'B', price: 20 }
];

const map = products.toMap(
  p => p.id,
  p => p.price
);

// map.get('A') === 10

list(n, process?, stepFunc?)

Generates a new array of length up to n using optional process and stepFunc. Starts from i = 0 and repeats while i < n.

  • If process is provided, pushes process(i); otherwise pushes i.
  • If stepFunc is provided, updates i = stepFunc(i); otherwise i++.

Signature

list(
  n: number,
  process?: (i: number) => any,
  stepFunc?: (i: number) => number
): any[]

Example

[].list(5); 
// [0, 1, 2, 3, 4]

[].list(5, i => i * 2); 
// [0, 2, 4, 6, 8]

[].list(5, i => i, i => i + 2);
// i = 0, 2, 4 => [0, 2, 4]

compact()

Returns a new array with all null and undefined values removed.

Signature

compact(): Array<T>

Example

[1, null, 2, undefined, 3].compact();
// [1, 2, 3]

partition(predicate)

Splits the array into two arrays based on a predicate:

  • First array: items where predicate(item) is true.
  • Second array: items where predicate(item) is false.

Signature

partition(predicate: (item: T) => boolean): [Array<T>, Array<T>]

Example

const nums = [1, 2, 3, 4, 5];
const [even, odd] = nums.partition(x => x % 2 === 0);

// even = [2, 4]
// odd  = [1, 3, 5]

3. Set & Membership Helpers

except(list)

Returns items that exist in this but not in list.

except(list: Array<T>): Array<T>

[1,2,3,4].except([2,4]); // [1,3]

contains(item), containsAll(list), containsAny(list)

Membership checks based on indexOf.

[1,2,3].contains(2);           // true
[1,2,3,4].containsAll([2,3]);  // true
[1,2,3].containsAny([3,5]);    // true

isEmpty(), hasItems(), random()

Check emptiness, existence of items, and get a random element (or null if empty).

4. Paging & Chunking

take(n), skip(n), takeLast(n)

Simple paging helpers for slicing from the start, skipping, or selecting from the end.

[1,2,3,4].take(2);       // [1,2]
[1,2,3,4].skip(2);       // [3,4]
[1,2,3,4,5].takeLast(2); // [4,5]

chunk(size)

Splits the array into sub-arrays of the specified size.

chunk(size: number): Array<Array<T>>

[1,2,3,4,5].chunk(2);
// [[1,2], [3,4], [5]]

5. Boolean Helpers

and(), or(), not()

Logical AND / OR over all items, and element-wise NOT.

[true, true, false].and();  // false
[false, false, true].or();  // true
[true, false].not();        // [false, true]

6. Ordering & Sorting

orderBy(compareFunc?) / orderByAsc(compareFunc?)

Description
Sorts the array in ascending order. If no compareFunc is provided, items are compared directly (suitable for numbers or strings). If compareFunc is provided, it is used to project each item to a sortable value. This method mutates the original array.

Signature

orderBy(compareFunc?: (item: T) => any): Array<T>
orderByAsc(compareFunc?: (item: T) => any): Array<T>

Example

[3, 1, 2].orderBy(); 
// [1, 2, 3]

const users = [
  { name: 'BB', age: 30 },
  { name: 'AA', age: 20 }
];

users.orderBy(u => u.age);
// [
//   { name: 'AA', age: 20 },
//   { name: 'BB', age: 30 }
// ]

orderByDesc(compareFunc?)

Description
Sorts the array in descending order. Without compareFunc it compares items directly; with compareFunc it sorts by the projected value. This method mutates the original array.

Signature

orderByDesc(compareFunc?: (item: T) => any): Array<T>

Example

[1, 3, 2].orderByDesc(); 
// [3, 2, 1]

const users = [
  { name: 'BB', age: 30 },
  { name: 'AA', age: 20 }
];

users.orderByDesc(u => u.age);
// [
//   { name: 'BB', age: 30 },
//   { name: 'AA', age: 20 }
// ]

orderByRandom()

Description
Randomizes the order of elements using Array.sort(() => Math.random() - 0.5). This produces a quick shuffle and mutates the original array. For a non-mutating, statistically better shuffle, use orderByShuffle().

Signature

orderByRandom(): Array<T>

Example

const items = [1, 2, 3, 4];

items.orderByRandom();
// e.g. [3, 1, 4, 2] (in-place)

orderByShuffle()

Description
Returns a new array with items shuffled using the Fisher–Yates algorithm. The original array is left unchanged, making it safer for pure functions and state management.

Signature

orderByShuffle(): Array<T>

Example

const a = [1, 2, 3, 4];
const shuffled = a.orderByShuffle();

// shuffled: random order
// a: [1, 2, 3, 4] (unchanged)

orderByLength() / orderByLengthAsc()

Description
Sorts items by their .length property in ascending order. Useful for arrays of strings, arrays or any object that exposes a numeric length. This method mutates the original array.

Signature

orderByLength(): Array<T>
orderByLengthAsc(): Array<T>

Example

['aaa', 'b', 'cc'].orderByLength();
// ['b', 'cc', 'aaa']

orderByLengthDesc()

Description
Sorts items by their .length property in descending order. This method mutates the original array.

Signature

orderByLengthDesc(): Array<T>

Example

['aaa', 'b', 'cc'].orderByLengthDesc();
// ['aaa', 'cc', 'b']

orderByText() / orderByTextAsc()

Description
Sorts an array of strings in ascending lexical order using localeCompare. Suitable for user-facing text where locale-sensitive ordering matters. This method mutates the original array.

Signature

orderByText(): Array<T>
orderByTextAsc(): Array<T>

Example

['b', 'c', 'a'].orderByText();
// ['a', 'b', 'c']

orderByTextDesc()

Description
Sorts an array of strings in descending lexical order using localeCompare. This method mutates the original array.

Signature

orderByTextDesc(): Array<T>

Example

['b', 'c', 'a'].orderByTextDesc();
// ['c', 'b', 'a']

7. Math & Statistics (Number Arrays)

These helpers are designed primarily for number[]. Many accept an optional condition function that can act as a predicate or a projection:

  • condition.length == 1 → treated as a predicate; the array is filtered first.
  • condition.length > 1 → treated as a projection; the function is applied to each item and the aggregate runs on the projected values.

max(condition?)

Returns the maximum numeric value in the array, or among filtered / projected values when condition is provided.

Signature

max(condition?: (item: T) => boolean | number): number

Example

[1, 5, 3].max();                  
// 5

[1, 5, 3].max(x => x < 5);      
// 3 (max of [1,3])

[1, 5, 3].max(x => x * 10);     
// 50 (max of [10,50,30])

min(condition?)

Returns the minimum numeric value in the array, or among filtered / projected values when condition is provided.

Signature

min(condition?: (item: T) => boolean | number): number

Example

[1, 5, 3].min();                  
// 1

[1, 5, 3].min(x => x > 1);      
// 3 (min of [5,3])

sum(condition?)

Computes the sum of values in the array. With condition, can sum either filtered items or projected values.

Signature

sum(condition?: (item: T) => boolean | number): number

Example

[1, 2, 3].sum();                        
// 6

[1, 2, 3, 4].sum(x => x % 2 === 0);  
// 6 (2 + 4)

const items = [
  { qty: 2, price: 10 },
  { qty: 1, price: 20 }
];
items.sum(x => x.qty * x.price);
// 40

avg(condition?)

Calculates the average (mean) of array values. With condition, uses filtered or projected values before averaging.

Signature

avg(condition?: (item: T) => boolean | number): number

Example

[1, 2, 3, 4].avg();                     
// 2.5

[1, 2, 3, 4].avg(x => x % 2 === 0);   
// 3 (avg of [2,4])

abs(condition?)

Returns a new array where each numeric value is converted to its absolute value (Math.abs). With condition, can apply to filtered or projected values.

Signature

abs(condition?: (item: T) => boolean | number): Array<T>

Example

[-1, 2, -3].abs();    
// [1, 2, 3]

pow(n)

Raises each numeric value to the power n using Math.pow and returns a new array.

Signature

pow(n: number): Array<T>

Example

[2, 3, 4].pow(2); 
// [4, 9, 16]

sqrt()

Applies Math.sqrt to each numeric value and returns a new array of square roots.

Signature

sqrt(): Array<T>

Example

[1, 4, 9].sqrt(); 
// [1, 2, 3]

Trigonometric helpers: sin(), cos(), tan(), asin(), acos(), atan()

Applies the corresponding Math.* trigonometric function to each numeric value and returns a new array.

Signature

sin(): Array<T>
cos(): Array<T>
tan(): Array<T>
asin(): Array<T>
acos(): Array<T>
atan(): Array<T>

Example

[0, Math.PI / 2].sin(); 
// [0, 1]

exp(), exp2(), exp10()

Exponential helpers applied per element:

  • exp()Math.exp(x)
  • exp2()2^x
  • exp10()10^x

Signature

exp(): Array<T>
exp2(): Array<T>
exp10(): Array<T>

Example

[0, 1].exp();    
// [1, Math.E]

[1, 2].exp2();   
// [2, 4]

[1, 2].exp10();  
// [10, 100]

Rounding helpers: floor(), ceil(), round()

Applies the corresponding rounding function from Math to each numeric value.

Signature

floor(): Array<T>
ceil(): Array<T>
round(): Array<T>

Example

[1.2, 1.8].floor(); 
// [1, 1]

[1.2, 1.8].ceil();  
// [2, 2]

[1.2, 1.8].round(); 
// [1, 2]

clamp(min, max)

Clamps each numeric value so that it stays within the inclusive range [min, max]. Values below min become min, values above max become max.

Signature

clamp(min: number, max: number): Array<T>

Example

[0, 5, 10, 15].clamp(3, 12);
// [3, 5, 10, 12]

median()

Computes the median of a numeric array:

  • Clones the array and sorts it ascending.
  • If length is odd → returns the middle element.
  • If length is even → returns the average of the two middle values.
  • If the array is empty → returns NaN.

Signature

median(): number

Example

[1, 3, 2].median();      
// 2

[1, 2, 3, 4].median();   
// (2 + 3) / 2 = 2.5

variance()

Computes the (population) variance of numeric values:

  • Uses avg() to compute the mean.
  • For each x, computes (x - mean)^2.
  • Returns the average of these squared differences.
  • If the array is empty → returns NaN.

Signature

variance(): number

Example

[1, 2, 3].variance();  
// 2/3 ≈ 0.6667

stdDev()

Computes the standard deviation of numeric values, defined as Math.sqrt(variance()).

Signature

stdDev(): number

Example

[1, 2, 3].stdDev();  
// ≈ 0.8165

mode()

Returns the most frequently occurring value in the array (numeric or string). Internally builds a frequency map and returns the key with the highest count. If the array is empty, returns NaN or undefined depending on implementation.

Signature

mode(): T

Example

[1, 2, 2, 3].mode();    
// 2

['a', 'b', 'a'].mode(); 
// 'a'

8. Async Helpers

mapAsync(mapper)

Async version of map, returning Promise<Array<R>> with Promise.all.

mapAsync<R>(mapper: (item: T, index: number) => Promise<R>): Promise<Array<R>>

forEachAsync(worker)

Async version of forEach, executing workers sequentially (awaiting each).

forEachAsync(
  worker: (item: T, index: number) => Promise<void>
): Promise<void>
const ids = [1, 2, 3];

await ids.forEachAsync(async (id, i) => {
  await saveToDb({ id, index: i });
});

Summary

The CKN Technology Core | Array Extensions provide a rich toolkit on top of native Array<T>: debug helpers, expressive querying and grouping, set/membership operations, paging and chunking, logical and sorting helpers, numeric and statistical functions, plus async utilities for modern workflows. Together they make collection handling in CKN-based projects more declarative, concise, and readable.