Twitter でループを使わずに1〜100まで出力するプログラム書ける?ってのが流れてきた。
「ループを使わずに1から100を順に出力するコードは書けますか」という質問に、凄腕たちがプログラム的な技巧を凝らした答えをする中、MSのデータサイエンティストが「1000/(999^2)を300桁まで計算すると答えが0.01002003…099100になるよ」とサラッと答えてて、どんな脳の使い方したら思い付くのそれ pic.twitter.com/Ng3dv4ZS4K
— 三崎律日@『奇書の世界史2』3月2日発売 (@i_kaseki) 2019年11月29日
元の質問は C++ で答えてくれって感じだったけど、大好きな JavaScript だとどう書けるのかやってみたくなったのでトライしてみた。
再帰
再帰はループに含まれるのかわからない。仮に含まれないなら再帰的に関数を呼び出して [1..100]
な配列を作るのが簡単そう
const zeroPadding = (digit) => { const zero = '0'.repeat(digit); // or Array( digit + 1 ).join('0'); return (n) => { return (zero + n).slice(- digit); } }; const addList = (i, arr) => { const a = [...arr].concat(zeroPadding(3)(i)); if (i === 100) { return a } return addList(i + 1, a); }; addList(1, []).join(' '); // => "001 002 003 004 005 006 007 008 009 // 010 011 012 013 014 015 016 017 018 019 // 020 021 022 023 024 025 026 027 028 029 // 030 031 032 033 034 035 036 037 038 039 // 040 041 042 043 044 045 046 047 048 049 // 050 051 052 053 054 055 056 057 058 059 // 060 061 062 063 064 065 066 067 068 069 // 070 071 072 073 074 075 076 077 078 079 // 080 081 082 083 084 085 086 087 088 089 // 090 091 092 093 094 095 096 097 098 099 100"
関数型っぽくゼロパディングするだけの関数を作ってみたけど、桁数決まってるから [...arr].concat(('000' + i).slice(-3));
で事足りる。
Array.from を使う
Array(100)
で要素が100個ある配列を作って、Array.from
の第2引数に値を変換する関数を渡して [1..100]
な配列を作る方法
Array.from
の値の変換って実質的に map なのでループを使ってるに該当はしてしまいそう。。。
Array.from(Array(100), (v, i) => ('000' + (i + 1)).slice(-3)).join(' '); // => "001 002 003 004 005 006 007 008 009 // 010 011 012 013 014 015 016 017 018 019 // 020 021 022 023 024 025 026 027 028 029 // 030 031 032 033 034 035 036 037 038 039 // 040 041 042 043 044 045 046 047 048 049 // 050 051 052 053 054 055 056 057 058 059 // 060 061 062 063 064 065 066 067 068 069 // 070 071 072 073 074 075 076 077 078 079 // 080 081 082 083 084 085 086 087 088 089 // 090 091 092 093 094 095 096 097 098 099 100"
Array.from
の map 関数で配列の値をインデックスを利用して 1〜100 にしている。
Array.from(arrayLike[, mapFn[, thisArg]])
arrayLike
… 配列に変換する配列風オブジェクトまたは反復可能オブジェクト
mapFn
(Optional) … 配列のすべての要素に対して呼び出される Map 関数。
thisArg
(Optional) …mapFn
を実行する時にthis
として使用する値。
console.log(Array.from([1, 2, 3], x => x + x)); // expected output: Array [2, 4, 6]cf. [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/from:title]
Array().keys() を使う
Array.keys()
で配列のインデックスが入った Array Iterator Object を取得できる。 Array Iterator Object は forEach
や map
メソッドを持っていないので、[...Array.keys()]
で配列に変換すれば Array.length
分のインデックスが順番に入った配列を取得できる。
const arr = [0,0,0].keys(); // => Array Iterator Object [...arr]; // => [0, 1, 2]
インデックスは 0
から始まるので 101 の長さの配列からインデックスの配列を作成して先頭の値を削除すれば [1..100] な配列ができあがる。
map 的なものが無いのでゼロパディングは出来なそうだけど、質問にある 1〜100 を出力することはできる。
[...Array(101).keys()].slice(1).join(' '); // => "1 2 3 4 5 6 7 8 9 // 10 11 12 13 14 15 16 17 18 19 // 20 21 22 23 24 25 26 27 28 29 // 30 31 32 33 34 35 36 37 38 39 // 40 41 42 43 44 45 46 47 48 49 // 50 51 52 53 54 55 56 57 58 59 // 60 61 62 63 64 65 66 67 68 69 // 70 71 72 73 74 75 76 77 78 79 // 80 81 82 83 84 85 86 87 88 89 // 90 91 92 93 94 95 96 97 98 99 100"
JavaScript に用意されている機能を使えば、1行でも書くことが出来ました。(内部的にループ使ってるとか分からないけど…)
パズルみたいなの好きなので楽しかったです。
_人人人人人人人人人人人人人人_
> まったく、JSは最高だぜ! <
 ̄YYYYYYYYYYYYYY^ ̄
[参考]
まったく、JSは最高だぜ!...