1
0

More than 3 years have passed since last update.

【javascript】自己満足のrange関数

Last updated at Posted at 2020-11-07

自己満足なので鼻で笑ってやってください。

概要

逆順・小数点・引数検査を意識しつつ、それなりの速度を出せたら良いな。
という想いで組んでました。
他の人のコードと比較した訳ではありませんが、今の私にはこれが限界。

幾つかコードを載せますが、やってる事はほぼ同じです。

range(from, to, step);
引数 変数名 既定値
1 from 0 起点の数値
2 to 0 起点からこの数値に向かう
3 step 1 負の値は指定しない
出力結果
//空の配列を返すパターン
console.log( range() );             //引数が空
console.log( range(-5, false) );    //第3引数までに数値以外が指定
console.log( range(-5, 5, 0) );     //stepに0が指定

//from,toが同値
console.log( range(5, 5) );         //[5]

//引数が1つ => 0に向かってstep1で生成
console.log( range(-5.5) );         //[-5.5, -4.5, -3.5, -2.5, -1.5, -0.5]
console.log( range(5.5) );          //[0.5, 1.5, 2.5, 3.5, 4.5, 5.5]

//引数が2つ => step1
console.log( range(-5, 5) );        //[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]
console.log( range(5, -5) );        //[5, 4, 3, 2, 1, 0, -1, -2, -3, -4, -5]

//引数が3つ => stepを指定
console.log( range(-5, 5, 2.5) );   //[-5, -2.5, 0, 2.5, 5]
console.log( range(5, -5, 2.5) );   //[5, 2.5, 0, -2.5, -5]

//4つ目以降の引数は影響なし
//負のstep値は絶対値で処理
console.log( range(-5, 5, -2, 2) );         //[-5, -3, -1, 1, 3, 5]
console.log( range(5, -5, 2, false, 2) );   //[5, 3, 1, -1, -3, -5]

コード1

  • 速度を意識したつもり
  • argumentsを使うためにアロー関数を使用しない
const range = function (from=0, to=0, step=1) {
    const array = new Array();

    //引数検査・調整
    const argLength = 2 in arguments ? 3 : arguments.length;
    for (let i = 0; i < argLength; i++) {
        if (Number.isFinite(arguments[i]) === false) return array;
    }
    switch (argLength) {
        case 0:
            return array;
        case 1:
            if (from > 0) {
                to = from;
                from = from - Math.floor(from);
            }
            break;
        case 3:
            if (step === 0) return array;
            step = Math.abs(step);
            break;
    }

    //本体
    if (from < to) {
        for (; from <= to; from += step) array.push(from);
    } else {
        for (; from >= to; from -= step) array.push(from);
    }
    return array;
};

コード2

  • 自由に書いたもの
  • コード1より遅い
const range = (...args) => {    //arguments(from=0, to=0, step=1)
    //引数検査・調整
    args = args.slice(0, 3);
    if (!args.every(Number.isFinite)) return [];

    let [from=0, to=0, step=1] = args;
    const comp = [
        () => null,
        () => from > 0 ? (to = from, from = from - Math.floor(from)) : true,
        () => true,
        () => step ? step = Math.abs(step) : null
    ];
    if ( comp[args.length]() === null ) return [];

    //本体
    const len = Math.abs(Math.ceil((from - to) / step)) + 1;
    if (from > to) step = -step;
    const calc = x => from + x * step;

    return [...Array(len).keys()].map(calc);
};

コード3(ジェネレーター関数)

  • コード1をジェネレーター関数に書き換えただけ
const range = function* (from=0, to=0, step=1) {
    //引数検査・調整
    const argLength = 2 in arguments ? 3 : arguments.length;
    for (let i = 0; i < argLength; i++) {
        if (Number.isFinite(arguments[i]) === false) return;
    }
    switch (argLength) {
        case 0:
            return;
        case 1:
            if (from > 0) {
                to = from;
                from = from - Math.floor(from);
            }
            break;
        case 3:
            if (step === 0) return;
            step = Math.abs(step);
            break;
    }

    //本体
    if (from < to) {
        for (; from <= to; from += step) yield from;
    } else {
        for (; from >= to; from -= step) yield from;
    }
};

最後に

うーん、色々と長い。

【javascript】一行で書かないrange関数 - Qiita
内容はこの記事の前に書いたコードなので見なくても問題ありません。

1
0
1

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
1
0