Sat Sep 13 17:50:38 JST 2014

Coffee Script リスト内包表記 (list comprehension)

Basic

ar = [1 .. 10]
(i for i in ar)
coffee -bc test.coffee
cat test.js
// Generated by CoffeeScript 1.7.1
var ar, i, _i, _len;

ar = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

for (_i = 0, _len = ar.length; _i < _len; _i++) {
  i = ar[_i];
  i;
}

では結果を保存するようにして、無駄な括弧を捨てる

ar = [1 .. 10]
list = i for i in ar

results to

// Generated by CoffeeScript 1.7.1
var ar, i, list, _i, _len;

ar = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

for (_i = 0, _len = ar.length; _i < _len; _i++) {
  i = ar[_i];
  list = i;
}

確かに保存されてる。

ブロック表現

ar = [1 .. 10]
list = if i % 2 == 0 then true else false for i in ar

results to

// Generated by CoffeeScript 1.7.1
var ar, i, list;

ar = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

list = (function() {
  var _i, _len, _results;
  if (i % 2 === 0) {
    return true;
  } else {
    _results = [];
    for (_i = 0, _len = ar.length; _i < _len; _i++) {
      i = ar[_i];
      _results.push(false);
    }
    return _results;
  }
})();

どうも、

list = (if i % 2 == 0 then true else (false for i in ar))

と解釈されてる。

じゃあ

list = (if i % 2 == 0 then true else false) for i in ar

とでもすればいいんだろうけれど、 LISP以外は括弧をダサいと考えなければいけないので、

閑話休題

純粋な for文は次の2パターンを持つ

for _ in _
  _
  _
_ for _ in _

先ほどの続き

インデントしてブロックで表現してあげよう

ar = [1 .. 10]
list = for i in ar
  if i % 2 == 0 then true else false

results to

// Generated by CoffeeScript 1.7.1
var ar, i, list;

ar = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

list = (function() {
  var _i, _len, _results;
  _results = [];
  for (_i = 0, _len = ar.length; _i < _len; _i++) {
    i = ar[_i];
    if (i % 2 === 0) {
      _results.push(true);
    } else {
      _results.push(false);
    }
  }
  return _results;
})();

continue, break

普通のforと同様に、ブロック表現することで複数行を書くことができる。 我々はもっと複雑なことを堂々と命令する権利を手に入れた。

ar = [1 .. 100]
list = for i in ar
  switch
    when i > 10 then break
    when i % 3 is 0 then continue
    else i

results to

// Generated by CoffeeScript 1.7.1
var ar, i, list, _i, _results;

ar = (function() {
  _results = [];
  for (_i = 1; _i <= 100; _i++){ _results.push(_i); }
  return _results;
}).apply(this);

list = (function() {
  var _j, _len, _results1;
  _results1 = [];
  for (_j = 0, _len = ar.length; _j < _len; _j++) {
    i = ar[_j];
    switch (false) {
      case !(i > 10):
        break;
      case i % 3 !== 0:
        continue;
      default:
        _results1.push(i);
    }
  }
  return _results1;
})();

push で結果を保存してるだけだから簡単だ。

[ 1, 2, 4, 5, 7, 8, 10 ]