0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[memo] TypeScriptでPythonのrange()っぽいものを使いたい

Last updated at Posted at 2023-02-27

はじめに

  • TypeScript で(例えば React の JSX の中でループするような場合に)Pythonの range() みたいなものが欲しくなることがありますよね
  • 通常は [...Array(num)].map([_, i] => ~) みたいな感じにしているけど、初見の人にわかりにくい気がする
  • 簡易的な関数を作ってみたので、とりあえずメモ

実装

一応、使いまわす前提なので export する形で記載しました。
使うところと同じファイルに書くなら export は取り除いた方が良いかも。

export function range(start: number, stop: number, step?: number): number[];
export function range(stop: number): number[];
export function range(...args:
    | [start: number, stop: number, step?: number]
    | [stop: number]
): number[] {
    if (args.length === 1) {
        const [stop] = args;
        return Array.from({length: stop}, (_, i) => i);
    } else {
        const [start, stop, step = 1] = args;
        if (step === 0) {
            throw new Exception(`range(${args})`);
        }
        return Array.from(
            { length: Math.ceil((stop - start) / step)},
            (_, i) => start + (i * step)
        );
    }
}

start とか step がいらないなら、以下だけでもいいかも。

export const range = (stop: number) => Array.from({length: stop}, (_, i) => i);

実際に配列を作ってしまうので、Python3 ではなく Python2 の range() 相当ですけどね。

間違いとか、もっと良い方法があったら教えてください。

性能対策

以下の記事にある @kawanet さんのコメントを参考に、性能対策版を考えてみた。

reduce() を使って、配列を 2 回作らない対策をしたもの。
ついでに配列にスプレット構文で展開するよりも fill() の方がほんのすこし速そうなので。

export function range(start: number, stop: number, step?: number): number[];
export function range(stop: number): number[];
export function range(...args:
    | [start: number, stop: number, step?: number]
    | [stop: number]
): number[] {
    if (args.length === 1) {
        const [stop] = args;
        return Array(stop).fill(0).reduce((_, __, i, a) => ((a[i] = i), a), []);
    } else {
        const [start, stop, step = 1] = args;
        if (step === 0) {
            throw new Exception(`range(${args})`);
        }
        return (Array(Math.ceil((stop - start) / step)).fill(0)
            .reduce((_, __, i, a) => ((a[i] = start + (i * step)), a), []));
    }
}

start とか step がいらない版:

export const range = (stop: number) => Array(stop).fill(0).reduce((_, __, i, a) => ((a[i] = i), a), []);

参考

↑下の方に連番生成のサンプルコードがあります。

↑Python3の range() のマニュアル。ちゃんと見るといろいろと違いますね。上記 TypeScript 版では start が省略できないとか。

↑関数のオーバーロードの書き方を参考にしました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?