Python
の内包表記のようにワンライナーで if-elseの条件分けをJavaScriptでできないかといつも思っていました。
普通に考えたらそこまで難しくないが、あまりこのような書き方を見なかったのでメモ。
たとえば、配列の値を条件分けしてそれぞれの値を集計したいタスクを考える。
一番シンプルに考えるのであれば、事前に変数を宣言しておき for文を回して
その中で変数にインクリメントするか、配列にpushするという選択肢が考えられる。
ただ、少しスマートではないと思ったので、reduce関数 の第二引数 initialValue に
配列を指定することでそのような要件を達成したいと考えた。
今回は以下のように0も含むような配列を考慮する
let input = [-1, 3, 4, -2, -3, 6, -7, 0, 0]
実現した実装は以下の通りである。
動作としてはreduce関数の第一引数内のアロー関数のなかで、第一引数には配列を、第二引数には numを指定する。第1引数には「蓄積された値」、第2引数には「現在の要素」となる。初期値として [0,0]
を渡している。numの条件次第で渡した値に前置インクリメントを加え加算していく。
reduce([callback],初期値)
関数におけるcallbackは前の結果の影響を受けるのでそのまま加算されていくという仕組みである。
let result1 = input.reduce(([positive, negative], num) => num > 0 ?
[++positive, negative] :
[positive, ++negative],
[0, 0])
console.log(result1) //この場合は集計値である[ 3, 6 ]を値として得られる。
また、コードの可読性は落ちるが、Javascriptの三項演算子は以下のようにすることで
if,else-if,elseのようにも記述可能である。
これを応用すれば、三つの条件に関して値を集計できそれぞれを値として保持できる。
let variable = (condition) ?
(true block) :
((condition2) ? (true block2) : (else block2))
let result2 = input.reduce(([positive, negative, zero], num) => num > 0 ?
([++positive, negative, zero]) :
((num < 0) ?
([positive, ++negative, zero]) : [positive, negative, ++zero]), [0, 0, 0])
console.log(result2) //この場合は集計値である[ 3, 4, 2 ]を値として得られる。
この書き方でいいなぁと思ったのは、事前に変数を定義しなくても状態を記録できる点にあると思う。
条件にもよるが、宣言しなくてもよい変数を定義することでコード量は増える可能性もあるので、今回の書き方は役に立てば幸いです。