rxdb
Version:
A local-first realtime NoSQL Database for JavaScript applications - https://rxdb.info/
182 lines (158 loc) • 5.07 kB
text/typescript
import type {
MaybePromise,
MaybeReadonly
} from '../../types/index.d.ts';
export function lastOfArray<T>(ar: T[]): T | undefined {
return ar[ar.length - 1];
}
/**
* shuffle the given array
*/
export function shuffleArray<T>(arr: T[]): T[] {
return arr.slice(0).sort(() => (Math.random() - 0.5));
}
export function randomOfArray<T>(arr: T[]): T {
const randomElement = arr[Math.floor(Math.random() * arr.length)];
return randomElement;
}
export function toArray<T>(input: T | T[] | Readonly<T> | Readonly<T[]>): T[] {
return Array.isArray(input) ? (input as any[]).slice(0) : ([input] as any);
}
/**
* Split array with items into smaller arrays with items
* @link https://stackoverflow.com/a/7273794/3443137
*/
export function batchArray<T>(array: T[], batchSize: number): T[][] {
array = array.slice(0);
const ret: T[][] = [];
while (array.length) {
const batch = array.splice(0, batchSize);
ret.push(batch);
}
return ret;
}
/**
* @link https://stackoverflow.com/a/15996017
*/
export function removeOneFromArrayIfMatches<T>(ar: T[], condition: (x: T) => boolean): T[] {
ar = ar.slice();
let i = ar.length;
let done = false;
while (i-- && !done) {
if (condition(ar[i])) {
done = true;
ar.splice(i, 1);
}
}
return ar;
}
/**
* returns true if the supplied argument is either an Array<T> or a Readonly<Array<T>>
*/
export function isMaybeReadonlyArray(x: any): x is MaybeReadonly<any[]> {
// While this looks strange, it's a workaround for an issue in TypeScript:
// https://github.com/microsoft/TypeScript/issues/17002
//
// The problem is that `Array.isArray` as a type guard returns `false` for a readonly array,
// but at runtime the object is an array and the runtime call to `Array.isArray` would return `true`.
// The type predicate here allows for both `Array<T>` and `Readonly<Array<T>>` to pass a type check while
// still performing runtime type inspection.
return Array.isArray(x);
}
export function isOneItemOfArrayInOtherArray<T>(ar1: T[], ar2: T[]): boolean {
for (let i = 0; i < ar1.length; i++) {
const el = ar1[i];
const has = ar2.includes(el);
if (has) {
return true;
}
}
return false;
}
/**
* Use this in array.filter() to remove all empty slots
* and have the correct typings afterwards.
* @link https://stackoverflow.com/a/46700791/3443137
*/
export function arrayFilterNotEmpty<TValue>(value: TValue | null | undefined): value is TValue {
if (value === null || value === undefined) {
return false;
}
return true;
}
export function countUntilNotMatching<T>(
ar: T[],
matchingFn: (v: T, idx: number) => boolean
): number {
let count = 0;
let idx = -1;
for (const item of ar) {
idx = idx + 1;
const matching = matchingFn(item, idx);
if (matching) {
count = count + 1;
} else {
break;
}
}
return count;
}
export async function asyncFilter<T>(array: T[], predicate: (item: T, index: number, a: T[]) => MaybePromise<boolean>): Promise<T[]> {
const filters = await Promise.all(
array.map(predicate)
);
return array.filter((...[, index]) => filters[index]);
}
/**
* @link https://stackoverflow.com/a/3762735
*/
export function sumNumberArray(array: number[]): number {
let count = 0;
for (let i = array.length; i--;) {
count += array[i];
}
return count;
}
export function maxOfNumbers(arr: number[]): number {
return Math.max(...arr);
}
/**
* Appends the given documents to the given array.
* This will mutate the first given array.
* Mostly used as faster alternative to Array.concat()
* because .concat() is so slow.
* @link https://www.measurethat.net/Benchmarks/Show/4223/0/array-concat-vs-spread-operator-vs-push#latest_results_block
*
* TODO it turns out that in mid 2024 v8 has optimized Array.concat()
* so it might be faster to just use concat() again:
* @link https://jsperf.app/qiqawa/10
*/
export function appendToArray<T>(ar: T[], add: T[] | readonly T[]): void {
/**
* Pre-increasing the array size has turned out
* to be way faster when big arrays must be handled.
* @link https://dev.to/uilicious/javascript-array-push-is-945x-faster-than-array-concat-1oki
*/
const addSize = add.length;
if (addSize === 0) {
return;
}
const baseSize = ar.length;
ar.length = baseSize + add.length;
for (let i = 0; i < addSize; ++i) {
ar[baseSize + i] = add[i];
}
}
/**
* @link https://gist.github.com/telekosmos/3b62a31a5c43f40849bb
*/
export function uniqueArray(arrArg: string[]): string[] {
return arrArg.filter(function (elem, pos, arr) {
return arr.indexOf(elem) === pos;
});
}
export function sortByObjectNumberProperty<T>(property: keyof T) {
return (a: T, b: T) => {
return (b as any)[property] - (a as any)[property];
}
}