素人がプログラミングを勉強していたブログ

プログラミング、セキュリティ、英語、Webなどのブログ since 2008

連絡先: twitter: @javascripter にどうぞ。

JSでrange

Pythonのrange(配列で返すほう)をJSで書く。

function range(from, to, step) {
  var i, a = [];
  if (typeof to == "undefined") {
    to = from;
    from = 0;
  }
  if (typeof step == "undefined")
    step = 1;
  if (step == 0)
    throw new TypeError("range() step argument must not be zero");
  if (from < to) {
    if (step > 0)
      for (i = from; i < to; i += step)
        a.push(i);
  } else {
    if (step < 0)
      for (i = from; i > to; i += step)
        a.push(i);
  }
  return a;
}

stepの正負によって分けて、同じようなコードが二つあるのがイマイチ。
次に、stepが負の場合には逆順に配列を作るようにして.reverse()するようにした物。

function range(from, to, step) {
  var i, a = [];
  if (typeof to == "undefined")
    return range(0, from, step);
  if (typeof step == "undefined")
    return range(from, to, 1);
  if (from > to)
    return range(to + 1, from + 1, -step).reverse();
  if (step == 0)
    throw new TypeError("range() step argument must not be zero");
  if (step > 0)
    for (i = from; i < to; i += step)
      a.push(i);
  return a;
}

reverseしたので速度が落ちる。+1している部分も分かりづらい。
どう書くと良いのだろう。
簡単なテスト:

function eqv(a, b) {
  function cmp(_, i) {
    return a[i] === b[i];
  }
  return a.length == b.length && a.every(cmp);
}

function assert(code, value) {
  var ok;
  try {
    ok = eqv(eval(code), value);
  } catch (ex) {
    console.error("%s: %o", code, ex);
    return;
  }
  if (ok)
    console.log("%s: %o", code, ok);
  else
    console.error("%s: %o", code, ok)
}

assert("range(0)", []);
assert("range(0, 0)", []);
assert("range(3, 2)", []);
assert("range(-1, 2, -1)", []);
assert("range(3, 0)", []);
assert("range(1)", [0]);
assert("range(2)", [0, 1]);
assert("range(0, 1)", [0]);
assert("range(1, 5, 2)", [1, 3]);
assert("range(-1, 2)", [-1, 0, 1]);
assert("range(-1, 2, 2)", [-1, 1]);
assert("range(3, 0, -1)", [3, 2, 1]);