イントロ
TypeScript勉強中
配列操作でgroupByっぽいメソッドが無いことを発見。
linqのnpmパッケージを使用すれば解決できるが
https://www.npmjs.com/package/linq
Enumerable.from(hoge).groupBy();
という具合に、Enumerableに食わせてあげる必要があった。
C#のLINQの書き方が好みなので
C#LIKE な ドット演算子でつなげて記述できるよう 試行錯誤してみた。
実装
array.extensions.ts
export {};
declare global {
interface Array<T>
{
groupBy<K extends PropertyKey>(callbackfn: (value: T, index: number, array: readonly T[]) => K): {key: K, values: T[]}[];
}
}
Array.prototype.groupBy = function<T, K extends PropertyKey>(callbackfn: (value: T, index: number, array: readonly T[]) => K): {key: K, values: T[]}[] {
const entities = this as T[];
return entities.reduce((ret, cur, idx, src) => {
const key = callbackfn(cur, idx, src);
let values = ret.find(e => e.key === key);
if (values === undefined) { ret.push({key: key, values: [cur]}); }
else { values.values.push(cur); }
return ret;
}, [] as {key: K, values: T[]}[]);
}
上記を実装することで [].groupBy()
というように Arrayの拡張メソッドを生やせるようになる
使用例
ユーザ配列内の rank
毎に グルーピングする例
index.ts
import './array.extensions';
class User {
constructor(
public name: string,
public rank: number,
) {}
}
let users: User[] = [
new User('aaa', 1),
new User('bbb', 2),
new User('ccc', 1),
new User('ddd', 3),
];
users.groupBy(e => e.rank)
.filter(e => e.key !== 2)
.forEach(e => {
console.log(`rank: ${e.key}`);
console.log(`names: ${e.values.map(e => e.name)}`);
});
結果.
rank: 1
names: aaa,ccc
rank: 3
names: ddd
まとめ
linq packageの方が機能がおおく優秀ではありますが、
.演算子で繋げたいという方はぜひ