memorandums

日々の生活で問題解決したこと、知ってよかったことなどを自分が思い出すために記録しています。

Arrayをconsole.logで出力したときの仕様ではまる⇒とりあえずtoString()を使う

2年生のゼミで,プログラミングコンテストチャレンジブックの輪読会をはじめました.2年生にはちょっと難しすぎたかなぁ...と後悔しているところです.

プログラミングコンテストチャレンジブック [第2版] ~問題解決のアルゴリズム活用力とコーディングテクニックを鍛える~ www.amazon.co.jp 2,641円 (2021年10月05日 09:03時点 詳しくはこちら) Amazon.co.jpで購入する

まだ,2章なんですが,僕もざーっとやっておこうと読んでたんです.昨晩の話です.ちなみにこの本の言語はC++です.

2−1に再帰を使って順列を作るコードが掲載されていて,これでなんか作れないかなぁと思ったのが運の尽きでした.ちなみにC++のコード片は以下の通りです.

const int MAX_N = 100;



bool used[MAX_N];

int perm[MAX_N];



void permutation1(int pos, int n) {

 if (pos == n) {

   for (int i=0; i<n; i++) {

     cout << perm[i] << " ";

   }

   cout << endl;

 }

 for (int i=0; i<n; i++) {

   if (!used[i]) {

     perm[pos] = i;

     used[i] = true;

     permutation1(pos+1, n);

     used[i] = false;

   }

 }

 return;

}

これをいつも遊んでいるp5.jsに移植してみたんですね.以下のような感じです.

let a = [];

let used = [];



function perm(pos, n) {

 if (pos == n) {

   console.log(a);

   return;

 }

 for (let i=0; i<n; i++){

   if (!used[i]) {

     a[pos] = i;

     used[i] = true;

     perm(pos+1, n);

     used[i] = false;

   }

 }

}



perm(0, 5);

実行結果はなぜか以下のように表示されました...なんじゃこりゃ?

スクリーンショット 2021-10-05 9.08.37

すべて同じなんですね...p5.jsを使ったせいだろうか?

上のコードをnodeのREPLに投げ込むと結果は以下です.期待通りです.

スクリーンショット 2021-10-05 9.10.12

Chromeのコンソールに投げ込むとnodeと同様に問題ないように見えます.

スクリーンショット 2021-10-05 9.11.29

で,ふと,上記の▲を押してみると...なんとなくヒントがありました.

スクリーンショット 2021-10-05 9.12.37

あれ?表示とオブジェクトをinspectした内容が不一致になります.なぜでしょう?console.logの仕様?Arrayの仕様?スコープの違い?なんだろう?

追跡のため,小さなサンプルを作ってみました.



let a = [0];

a[0] += 1;

console.log(a);

a[0] += 1;

console.log(a);

p5.jsでは以下の通りです.a[0]のである2が2回出力されています.

スクリーンショット 2021-10-05 9.57.56

Chromeとnodeでは上記の問題は問題なく[1]と[2]が期待通りに表示されました.

console.logの引数に配列が与えられたときに,文字列化するはずなんですが,この仕様がnodeやChromeやp5jsでは違うような気がします.p5.jsではconsole.logが再定義されているようです.詳しくは追っていませんが.

ちなみに,p5.jsであっても以下のように配列に添え字をつければちゃんと期待した値が返ってきます.



let a = [0];

a[0] += 1;

console.log(a[0]);

a[0] += 1;

console.log(a[0]);

これ以上,追うのは面倒になってきたので,とりあえずの結論は以下になりました.

console.logに配列を与えて表示しようとするときには注意が必要で,はまらないようにするためには(僕みたいに横着しないで)添字をちゃんと与えるか?文字列化のメソッド(toString())を呼び出せば安心だよ.

toString()を使った例は以下ですね.

let a = [0];

a[0] += 1;

console.log(a.toString());

a[0] += 1;

console.log(a.toString());

さらに,順列を作るコードをちゃんと表示するようにするなら,以下になります.

let a = [];

let used = [];



function perm(pos, n) {

 if (pos == n) {

   console.log(a.toString());

   return;

 }

 for (let i=0; i<n; i++){

   if (!used[i]) {

     a[pos] = i;

     used[i] = true;

     perm(pos+1, n);

     used[i] = false;

   }

 }

}



perm(0, 5);

日常的にJSを触っている人にとってはこんなことは常識なんでしょうね.とりあえず,何となくですがスッキリしました😁

でも,なんで添字をつけないときには配列オブジェクトの最終状態の値をconsole.logは表示しようとするのだろう?処理を遅延しているのだろうか?ここは謎です.