Skip to content

Instantly share code, notes, and snippets.

@vitaly-t
Last active October 2, 2024 13:45
Show Gist options
  • Select an option

  • Save vitaly-t/2c868874738cc966df776f383e5e0247 to your computer and use it in GitHub Desktop.

Select an option

Save vitaly-t/2c868874738cc966df776f383e5e0247 to your computer and use it in GitHub Desktop.
Logically concatenates arrays
/**
* Iterable arrays chain, extended for "getLength" and "at" accessor.
*/
export interface IArraysChain<T> extends RelativeIndexable<T>, Iterable<T> {
/**
* Calculates total length of all input arrays combined.
*/
getLength(): number;
}
export function chainArrays(): IArraysChain<unknown>;
export function chainArrays<A>(a: ArrayLike<A>): IArraysChain<A>;
export function chainArrays<A, B>(a: ArrayLike<A>, b: ArrayLike<B>): IArraysChain<A | B>;
export function chainArrays<A, B, C>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>): IArraysChain<A | B | C>;
export function chainArrays<A, B, C, D>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>): IArraysChain<A | B | C | D>;
export function chainArrays<A, B, C, D, E>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>): IArraysChain<A | B | C | D | E>;
export function chainArrays<A, B, C, D, E, F>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>, f: ArrayLike<F>): IArraysChain<A | B | C | D | E | F>;
export function chainArrays<A, B, C, D, E, F, G>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>, f: ArrayLike<F>, g: ArrayLike<G>): IArraysChain<A | B | C | D | E | F | G>;
export function chainArrays<A, B, C, D, E, F, G, H>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>, f: ArrayLike<F>, g: ArrayLike<G>, h: ArrayLike<H>): IArraysChain<A | B | C | D | E | F | G | H>;
export function chainArrays<A, B, C, D, E, F, G, H, I>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>, f: ArrayLike<F>, g: ArrayLike<G>, h: ArrayLike<H>, i: ArrayLike<I>): IArraysChain<A | B | C | D | E | F | G | H | I>;
export function chainArrays<A, B, C, D, E, F, G, H, I, J>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>, f: ArrayLike<F>, g: ArrayLike<G>, h: ArrayLike<H>, i: ArrayLike<I>, j: ArrayLike<J>): IArraysChain<A | B | C | D | E | F | G | H | I | J>;
/**
* Logically concatenates arrays (chains them), into an iterable.
*/
export function chainArrays<T>(...arr: Array<ArrayLike<T>>): IArraysChain<T> {
return {
getLength() {
return arr.reduce((a, c) => a + c.length, 0);
},
at(i: number): T | undefined {
for (let j = 0; j < arr.length; j++) {
if (i < arr[j].length) {
return arr[j][i];
}
i -= arr[j].length;
}
},
[Symbol.iterator](): Iterator<T> {
let i = 0, k = -1, a: ArrayLike<T> = [];
return {
next(): IteratorResult<T> {
while (i === a.length) {
if (++k === arr.length) {
return {done: true, value: undefined};
}
a = arr[k];
i = 0;
}
return {done: false, value: a[i++]};
}
};
}
}
}
export function chainArraysReverse(): IArraysChain<unknown>;
export function chainArraysReverse<A>(a: ArrayLike<A>): IArraysChain<A>;
export function chainArraysReverse<A, B>(a: ArrayLike<A>, b: ArrayLike<B>): IArraysChain<A | B>;
export function chainArraysReverse<A, B, C>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>): IArraysChain<A | B | C>;
export function chainArraysReverse<A, B, C, D>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>): IArraysChain<A | B | C | D>;
export function chainArraysReverse<A, B, C, D, E>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>): IArraysChain<A | B | C | D | E>;
export function chainArraysReverse<A, B, C, D, E, F>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>, f: ArrayLike<F>): IArraysChain<A | B | C | D | E | F>;
export function chainArraysReverse<A, B, C, D, E, F, G>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>, f: ArrayLike<F>, g: ArrayLike<G>): IArraysChain<A | B | C | D | E | F | G>;
export function chainArraysReverse<A, B, C, D, E, F, G, H>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>, f: ArrayLike<F>, g: ArrayLike<G>, h: ArrayLike<H>): IArraysChain<A | B | C | D | E | F | G | H>;
export function chainArraysReverse<A, B, C, D, E, F, G, H, I>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>, f: ArrayLike<F>, g: ArrayLike<G>, h: ArrayLike<H>, i: ArrayLike<I>): IArraysChain<A | B | C | D | E | F | G | H | I>;
export function chainArraysReverse<A, B, C, D, E, F, G, H, I, J>(a: ArrayLike<A>, b: ArrayLike<B>, c: ArrayLike<C>, d: ArrayLike<D>, e: ArrayLike<E>, f: ArrayLike<F>, g: ArrayLike<G>, h: ArrayLike<H>, i: ArrayLike<I>, j: ArrayLike<J>): IArraysChain<A | B | C | D | E | F | G | H | I | J>;
/**
* Logically concatenates arrays (chains them), into a reversed iterable.
*/
export function chainArraysReverse<T>(...arr: Array<ArrayLike<T>>): IArraysChain<T> {
return {
getLength() {
return arr.reduce((a, c) => a + c.length, 0);
},
at(i: number): T | undefined {
for (let j = arr.length - 1; j >= 0; j--) {
if (i < arr[j].length) {
return arr[j][arr[j].length - (i + 1)];
}
i -= arr[j].length;
}
},
[Symbol.iterator](): Iterator<T> {
let i = -1, k = arr.length, a: ArrayLike<T>;
return {
next(): IteratorResult<T> {
while (i < 0) {
if (--k < 0) {
return {done: true, value: undefined};
}
a = arr[k];
i = a.length - 1;
}
return {done: false, value: a[i--]};
}
};
}
}
}
@guest271314
Copy link

@vitaly-t I've done this multiple ways; using various means. I think writing data to a contiguous block of memory can be simpler than trying to manage a superimposition of indexes over N Arrays. If that approach works for you, great. If you are interested in the different ways I've done this let me know and I'll share.

@vitaly-t
Copy link
Author

vitaly-t commented Oct 2, 2024

As there was no way to update "length" when a source array changes, without a super-slow proxy, I had to just replace length with getLength method.

This way, this code will retain its maximum performance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment