Last active
December 11, 2023 09:56
-
-
Save bigmistqke/69ea9bad0784bfe297d821c6db982468 to your computer and use it in GitHub Desktop.
experiments with mutable array-methods
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ArrayInPlace<T = number> extends Array { | |
commands: Command<T>[] = []; | |
constructor(values: T[]) { | |
super(); | |
for (let i = 0; i < Math.floor(values.length / 100_000); i++) { | |
Array.prototype.push.apply( | |
this, | |
values.slice(i * 100_000, (i + 1) * 100_000), | |
); | |
} | |
} | |
mapInPlace(fn: (value: T, index: number) => T) { | |
for (let index = 0; index < this.length; index++) { | |
this[index] = fn(this[index], index); | |
} | |
return this; | |
} | |
filterInPlace(fn: (value: T, index: number) => boolean) { | |
let deleteCount = 0; | |
const length = this.length; | |
for (let index = length - 1; index >= 0; index--) { | |
if (!fn(this[index], index)) { | |
deleteCount++; | |
if (index === 0) { | |
Array.prototype.splice(index, deleteCount); | |
} | |
continue; | |
} | |
if (deleteCount > 0) { | |
this.splice(index, deleteCount); | |
} | |
} | |
return this; | |
} | |
set(index: number, value: T) { | |
this[index] = value; | |
return this; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const IS_MAP = Symbol(); | |
const IS_FILTER = Symbol(); | |
const IS_SET = Symbol(); | |
type SetFn = (() => void) & { type?: typeof IS_SET }; | |
type MapFn<T> = ((value: T, index: number) => T) & { type: typeof IS_MAP }; | |
type FilterFn<T> = ((value: T, index: number) => boolean) & { | |
type: typeof IS_FILTER; | |
}; | |
type Command<T> = MapFn<T> | SetFn | FilterFn<T>; | |
/** | |
* Array-like data structure with mutable, lazily executed methods. | |
*/ | |
class LazyMutable<T = number> { | |
private _values: T[]; | |
commands: Command<T>[] = []; | |
constructor(values: T[]) { | |
this._values = values; | |
} | |
private _run() { | |
for (const command of this.commands) { | |
switch (command.type) { | |
case IS_MAP: | |
for (let index = 0; index < this._values.length; index++) { | |
this._values[index] = command(this._values[index], index); | |
} | |
break; | |
case IS_FILTER: | |
let deleteCount = 0; | |
const length = this._values.length; | |
for (let index = length - 1; index >= 0; index--) { | |
if (!command(this._values[index], index)) { | |
deleteCount++; | |
if (index === 0) { | |
this._values.splice(index, deleteCount); | |
} | |
continue; | |
} | |
if (deleteCount > 0) { | |
this._values.splice(index, deleteCount); | |
} | |
} | |
break; | |
default: | |
command(); | |
break; | |
} | |
} | |
this.commands = []; | |
} | |
/** lazily executed */ | |
map(fn: (value: T, index: number) => T) { | |
const _fn = fn as MapFn<T>; | |
_fn.type = IS_MAP; | |
this.commands.push(_fn); | |
return this; | |
} | |
/** lazily executed */ | |
filter(fn: (value: T, index: number) => boolean) { | |
const _fn = fn as FilterFn<T>; | |
_fn.type = IS_FILTER; | |
this.commands.push(_fn); | |
return this; | |
} | |
/** lazily executed */ | |
set(index: number, value: T) { | |
const _fn = (() => void (this._values[index] = value)) as SetFn; | |
_fn.type = IS_SET; | |
this.commands.push(_fn); | |
return this; | |
} | |
/** immediately executed */ | |
find = (fn: (value: T, index: number) => boolean) => ( | |
this._run(), this._values.find(fn) | |
); | |
/** immediately executed */ | |
sort = () => (this._run(), this._values.sort()); | |
/** immediately executed */ | |
forEach = (fn: (value: T, index: number) => void) => ( | |
this._run(), this._values.forEach(fn) | |
); | |
/** immediately executed */ | |
reduce = ( | |
fn: (accumulator: T, value: T, index: number, values: T[]) => T, | |
) => (this._run(), this._values.reduce(fn)); | |
/** immediately executed */ | |
values = () => (this._run(), this._values); | |
/** immediately executed */ | |
get = (index: number) => (this._run(), this._values[index]) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Mutable<T = number> { | |
private _values: T[]; | |
commands: Command<T>[] = []; | |
constructor(values: T[]) { | |
this._values = values; | |
} | |
map(fn: (value: T, index: number) => T) { | |
for (let index = 0; index < this._values.length; index++) { | |
this._values[index] = fn(this._values[index], index); | |
} | |
return this; | |
} | |
filter(fn: (value: T, index: number) => boolean) { | |
let deleteCount = 0; | |
const length = this._values.length; | |
for (let index = length - 1; index >= 0; index--) { | |
if (!fn(this._values[index], index)) { | |
deleteCount++; | |
if (index === 0) { | |
Array.prototype.splice(index, deleteCount); | |
} | |
continue; | |
} | |
if (deleteCount > 0) { | |
this._values.splice(index, deleteCount); | |
} | |
} | |
return this; | |
} | |
set(index: number, value: T) { | |
this._values[index] = value; | |
return this; | |
} | |
find = (fn: (value: T, index: number) => boolean) => this._values.find(fn); | |
sort = () => this._values.sort(); | |
forEach = (fn: (value: T, index: number) => void) => this._values.forEach(fn); | |
reduce = (fn: (accumulator: T, value: T, index: number, values: T[]) => T) => | |
this._values.reduce(fn); | |
values = () => this._values; | |
get = (index: number) => this._values[index]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment