JavaScript for文の再設計。for_関数を作りました。

JavaScript for文の再設計。for_関数を作りました。:


for文がいろいろめんどうと気がついた。

初心者向けのfor文の記事を書いてみました。

JavaScript forループ | プログラミングアカデミー ゼロプラスワン
https://zero-plus-one.jp/javascript/javascript-forloop/

で、あらためてめんどうな事に気がついたのですが、

for (let i = 0; i <= count() - 1; i += 1) { 
  console.log(i); 
} 
for (let i = 0, imax = count() - 1; i <= imax; i += 1) { 
  console.log(i); 
} 
この二種類の書き方のどっちがいいとか、パフォーマンスがどっちがいいとか、いちいち考えなければいけないことが、うざいなーと思いました。名前はどうでもいいとして、imaxなんていう一時変数を持つのも変な話です。

あとは、二重ループからの脱出は、こんなふうに書かないと実現できないような気がします。違いましたっけ?適当なコードです。

for (let i = 0; i <= iCount()-1; i += 1) { 
  let breakFlag = false; 
  for (let j = 0; j <= jCount()-1; j += 1) { 
    if (i === x) { 
      breakFlag = true; 
      break; 
    } 
  } 
  if (breakFlag === tue) { break } 
} 
あるいは、gotoを使うとか、確かそういう話だった気がします。二重ループを抜けるときだけgotoを使うとか聞いたことがあるようなないようなです。

こういうのは言語仕様から間違っているんじゃないのか、と思ってしまいましたので、forを再設計して実装してみました。

既存のforを上書きはできないので、[for_]という関数で実現してみます。

前に書いた、if関数とか、switch関数のシリーズみたいなもんですかね。

JavaScriptの三項演算子が読みにくいらしいので、if式ならぬ if関数を作りました。そしてもっと読みにくい感。 - Qiita
https://qiita.com/standard-software/items/794724427fcee1cbd00b

JavaScript で if式っぽく動くようなswitch式...というかswitch関数作ったよ。 - Qiita
https://qiita.com/standard-software/items/111a0cfaf0e56d547d70


for_関数の実装

結構簡単でした。

const for_ = (start, end, increment, func) => { 
  // start, end , increment は整数値とする 
  // increment は 0 は許容しないとする 
  // start < end の場合は 1 <= increment 
  // end < start の場合は increment <= -1 とする 
 
  var i = start; 
  var condition = 
    1 <= increment 
      ? (i) => (i <= end)  
      : (i) => (end <= i) 
  while(condition(i)) { 
    if (func(i) === false) { 
      return false; 
    } 
    i += increment; 
  } 
  return true; 
}; 
構文としては

for_(開始Index, 終了Index, 加算値, ループ時実行関数)

となります。

ループ時実行関数で、return する場合は continue できて return false すると breakして、for_の戻り値に値が伝達されます。

次のように記載できます。 i とか j はループ変数で、二重ループを記載しています。

// 通常のループ 
// i が 1,2,3 と変化して、その中で、j が 1,2,3 と変化します。 
for_(1, 3, 1, (i) => { 
  console.log('i', i); 
  for_(1, 3, 1, (j, result)=>{ 
    console.log('j', j); 
  }); 
}); 
 
// continue したい場合は return する 
// i が 1,2,3 と変化して、その中で、j が 1,3 と変化します。 
for_(1, 3, 1, (i) => { 
  console.log('i', i); 
  for_(1, 3, 1, (j, result)=>{ 
    if (j === 2) { return } 
    console.log('j', j); 
  }); 
}); 
 
// break したい場合は return false する 
// i が 1,2,3 と変化して、その中で、j が 1 と表示されます。 
for_(1, 3, 1, (i) => { 
  console.log('i', i); 
  for_(1, 3, 1, (j, result)=>{ 
    if (j === 2) { return false } 
    console.log('j', j); 
  }); 
}); 
 
// 他段階の break をしたい場合は for_ の戻り値を return します 
// i が 1 と表示され、その中で、j が 1 と表示されます。 
for_(1, 3, 1, (i) => { 
  console.log('i', i); 
  return for_(1, 3, 1, (j, result)=>{ 
    if (j === 2) { return false } 
    console.log('j', j); 
  }); 
}); 
こんな感じで、forの代わりの構文を作ることができるようです。


追加で改良も可能かもしれない。

以前、forLoop関数というものを作ったことがありました。こちらは、二重ループとか考えられてないのですが、ループ時の全てで関数実行か、最初、最後、あるいは中間、で関数をわけてみています。

stsLib.js/stslib_core.js at master · standard-software/stsLib.js · GitHub
https://github.com/standard-software/stsLib.js/blob/master/Source/stsLib.js/stslib_core.js

_.forLoop = function(start, end, 
        funcAll, funcFirst, funcMiddle, funcLast) { 
 
        c.assert(t.isInts(start, end)); 
        var funcEmpty = function() { return; }; 
        funcAll = t.ifUndefinedValue(funcAll, funcEmpty); 
        funcFirst = t.ifUndefinedValue(funcFirst, funcEmpty); 
        funcMiddle = t.ifUndefinedValue(funcMiddle, funcEmpty); 
        funcLast = t.ifUndefinedValue(funcLast, funcEmpty); 
        for (var i = start; i <= end; i += 1) { 
          funcAll(i); 
          if (i === start) { 
            funcFirst(i); 
          } else if (i !== end) { 
            funcMiddle(i); 
          } 
          if (i === end) { 
            funcLast(i); 
          } 
        } 
      }; 
こんな改良も行えるかもしれないですね。

いろいろ試して動作確認したりして、楽しむのもよいでしょう。

ご参考にどうぞです。

コメント

このブログの人気の投稿

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-04-30 23:37:32 RSSフィード2021-04-30 23:00 分まとめ(42件)

投稿時間:2023-02-05 02:09:04 RSSフィード2023-02-05 02:00 分まとめ(9件)