主語を入れ替えるか目的語を入れ替えるか
ちょっとしたスクリプトで、"+foo" という文字列を "OKs" という配列に、"-bar" という文字列を "NGs" という配列に入れる、という必要が生じました。
var OKs = [], NGs = []; "+foo -bar +baz ...".replace(/([-+])(\S+)/g, function(_, pm, value) { if (pm == "+") OKs.push(value); else NGs.push(value); });
こういうのは出来れば一行で書きたいですよね? ということで幾つかバリエーションを考えてみました。
ふつうの三項演算:
pm == "+" ? OKs.push(value) : NGs.push(value)
push(value) が共通の操作であることに気付きます。こんな場合は:
(pm == "+" ? OKs : NGs).push(value)
と、括弧でメソッドの動作主体 (主語) をまとめてしまうことが出来ます。
逆のやり方もあります (と言うか先にこっちを思いつきました):
Array.prototype.push.call(pm == "+" ? OKs : NGs, value) // あるいは [].push.call(pm == "+" ? OKs : NGs, value)
この場合、メソッドの動作主体は Array クラスまたは任意のインスタンスであり、その適用対象 (間接目的語) をどちらにするかを選択している、と捉えることができます。
どっちの発想が自然なのかな? ということをふと思ったもので、書いてみました。
ちなみに、スクリプトというのはこういうものです:
register_command("!|filter", function() { var OKs = [], NGs = []; Array.from(arguments).join(" ").replace(/([-+])(\S+)/g, function(_, pm, folder) { Array.prototype.push.call(pm == "+" ? OKs : NGs, folder); }); if (!(OKs.length || NGs.length)) return; subs.model.load(subs.model.list.filter(function(v) { return NGs.length ? !NGs.some(function(x){return v.folder.match(x)}) : OKs.some(function(x){return v.folder.match(x)}); })); subs.update(); var joinp = function(ary, sep) { return sep+ary.join(sep) }; message([ "Filtered subs:", joinp.apply(null, NGs.length ? [NGs," -"] : [OKs," +"]) ].join("")); });
livedoor Reader で、フィード一覧のツリー構造を保ったままフォルダ単位で絞込みをする、というものです。主にレート表示での利用を念頭に置いています。
例えば今は趣味系は消したいとか、技術系だけ表示したい、みたいなことが出来ます。
これまでレートの中に色んなフィードが混在するのを避けようとして、重要度よりも内容でレート付けする (ニュース系は 5、技術系は 4 みたいに) という、間違った使い方をしていたんですが、それを何とかするために作ってみました。
vi コマンドで ":! -hobby" とすると "hobby" というフォルダのフィードだけが消えます。逆に "+" を前置するとそのフォルダだけが表示されます。
条件を複数指定することも可能ですが、"+" と "-" を混在させることは出来ません ("-" の条件だけが有効になります)。
私みたいにフィードをきっちりフォルダ管理している人にしか意味無いですが、他のフィルター方法を色々と考えてみるのも面白いかも知れません。
追記 [20061011]:
三項演算子の代わりに "&&" と "||" の組み合わせでも OK ですね。
例:
Array.prototype.push.call(pm == "+" && OKs || NGs, folder);
pm の値が "+" であれば OKs が、そうでなければ NGs が論理式の値となります (感覚的にブール値になると思ってしまいがちかも知れませんが、そうではないということです)。
ただし、"&&" の次に来るものが「真」と評価されるかどうかに注意する必要があります。例えば、もし空の配列が「偽」と評価されるなら (JavaScript では「真」ですが)、上の表現では正常に動作しないことになります (全て NGs に push されてしまう)。