神メソッド
もしかして: 神クラス
from 2024/02/01
Summer498.icon
ワイの過去に作ったプログラムから$ \argmin,\argmax,\min,\maxの全てを1つのメソッドから呼び出せるようにした神メソッドを発掘した
作ってるときは超楽しいが、保守のときに「あ~、楽しくて作っちゃったのねん……。でもやっぱシンプルな実装のほうがいいわ」ってなる
MusicAnalyzer-Server/chordToRoman/src/lib/Graph/Graph.ts at main · Summer498/MusicAnalyzer-Server · GitHub
code:ts
class MaxCalculableArray<T> extends Array<T> {
#args: T[][];
#values: number[];
#memo_funcs: (((i: T) => number) | undefined)[];
constructor(...items: T[]) {
super(items.length);
this.#args = this[0, [this0]]
this.#values = Infinity, -Infinity;
this.#memo_funcs = undefined, undefined;
items.forEach((_, i) => { thisi = itemsi; });
}
#willRenew: ((val: number) => boolean)[] = [
val => val < this.#values0,
val => val > this.#values1
]
#renew_min_or_max(f: (i: T) => number, is_max: number) {
this.#argsis_max = [this0];
this.#valuesis_max = (is_max) ? -Infinity : Infinity;
for (const i of this) {
const val = f(i);
if (this.#willRenewis_max(val)) {
this.#argsis_max = i;
this.#valuesis_max = val;
continue;
}
if (val == this.#valuesis_max) { this.#argsis_max.push(i); }
}
}
#checkCache(f: (i: T) => number, is_max: number) {
if (this.#memo_funcsis_max === f) { return; }
this.#renew_min_or_max(f, is_max);
this.#memo_funcsis_max = f;
}
min(f: (i: T) => number) { this.#checkCache(f, 0); return this.#values0; }
argMin(f: (i: T) => number) { this.#checkCache(f, 0); return this.#args00; }
argMins(f: (i: T) => number) { this.#checkCache(f, 0); return this.#args0; }
max(f: (i: T) => number) { this.#checkCache(f, 1); return this.#values1; }
argMax(f: (i: T) => number) { this.#checkCache(f, 1); return this.#args10; }
argMaxes(f: (i: T) => number) { this.#checkCache(f, 1); return this.#args1; }
}
ここまで来るとコピペのほうが善だわ
普通の配列を一旦 new MaxCalculableArray(...arr); でクラス化しなきゃいけないのが💩ポイント
当時は for ループが嫌いだったからこんな事をしていたな
思想が強い
その時はまっている手法で書いちゃうことよくあるtakker.icon
これがクソゴツいのはクラスになってるせい
リファクタリング後も結局神メソッドのままだったがダイエット大成功
code:ts
type: Comparition = (a:number, b:number) => boolean;
const is_lesser: Comparition = (a,b) => a<b;
const is_greater: Comparition = (a,b) => a>b;
const argsMinMax = (f: (i:T) => number, space: T[], compare:Comparition) => {
let val = (compare(0,1)) ? Infinity : -Infinity;
const args: number[] = [];
space.foreach(e => {
const res = f(e);
if(compare(res, val)){
args = e;
val = res;
}
else if(res===val){ args.push(e); }
})
return {val, args}
}
const min = (f: (i:T) => number, space: T[]) => argsMinMax(f, space, is_lesser).val;
const max = (f: (i:T) => number, space: T[]) => argsMinMax(f, space, is_greater).val;
const argsMin = (f: (i:T) => number, space: T[]) => argsMinMax(f, space, is_lesser).args;
const argsMax = (f: (i:T) => number, space: T[]) => argsMinMax(f, space, is_greater).args;
const argMin = (f: (i:T) => number, space: T[]) => argsMinMax(f, space, is_lesser).args0;
const argMax = (f: (i:T) => number, space: T[]) => argsMinMax(f, space, is_greater).args0;
なおこのコードのテストはしていない
思い出して手打ちしてるだけ
https://deno.land/std@0.214.0/collections/mod.ts に同じことできる函数がありそうtakker.icon