CsharpのLINQで紹介されている「連続するキーで結果をグループ化する」をTypescriptで実現するやり方
こんにちわ。nap5です。
CsharpのLINQで紹介されている「連続するキーで結果をグループ化する」をTypescriptで実現するやり方の紹介です。
元ネタはこちらになります。
前回の記事で紹介したpartitionByを使って実現できます。
import { Path } from "dot-path-value";
export type TRow = Record<string, unknown>;
export const compare = <T extends TRow>(fields: Path<T>[], a: T, b: T): number => {
for (const field of fields) {
if (a[field] < b[field]) return -1;
if (a[field] > b[field]) return 1;
}
return 0;
};
export const partitionBy = <T extends TRow>(data: T[], fields: Path<T>[]): T[][] =>
data.reduce((acc: T[][], row: T) => {
if (
acc.length > 0 &&
compare(
fields,
acc[acc.length - 1][acc[acc.length - 1].length - 1],
row
) === 0
) {
// 現在の行と直前のパーティションの最後の行が指定されたフィールドすべてで同じ場合に
// 直前のパーティションに現在の行を追加する
acc[acc.length - 1].push(row);
} else {
// 新しいパーティションを作成し、現在の行を追加する
acc.push([row]);
}
return acc;
}, []);
このpartitionByを使うと以下のように実装できます。
import { describe, test, expect } from "vitest";
import { bind, bindTo, map } from "fp-ts/lib/Identity";
import { pipe } from "fp-ts/lib/function";
import { partitionBy } from "./utils/dataUtil";
// @see https://learn.microsoft.com/ja-jp/dotnet/csharp/linq/group-results-by-contiguous-keys
describe("連続するキーで結果をグループ化する", () => {
type Item = {
key: string;
value: string;
};
const inputData: Item[] = [
{ key: "A", value: "We" },
{ key: "A", value: "think" },
{ key: "A", value: "that" },
{ key: "B", value: "LINQ" },
{ key: "C", value: "is" },
{ key: "A", value: "really" },
{ key: "B", value: "cool" },
{ key: "B", value: "!" },
];
test("Use -> partitionBy", () => {
const outputData = pipe(
inputData,
bindTo("input"),
bind("partitioned", ({ input }) => partitionBy(input, ["key"])),
bind("output", ({ partitioned }) =>
partitioned.map((g) => g.map((d) => d.value))
),
map(({ output }) => output)
);
expect(outputData).toStrictEqual([
["We", "think", "that"],
["LINQ"],
["is"],
["really"],
["cool", "!"],
]);
});
});
demo code.
簡単ですが、以上です。