• ベストアンサー

配列への大量コピーってあるの?

今,単純に「,」で区切られたデータが大量に続くテキストファイルがあっとします。(もちろん有限ですが) 1,2,3,4,5,6,7,8,9,10,11,12・・・,9999兆 このテキストデータを,javascriptで読み込んでresponseTextに入れたものを, var res = oj.responseText; のようにresにします。 この後, rows = res.split(','); のように,それぞれの数字を配列に入れたとします。 このとき,この配列にデータを入れるという作業は,実際に,rows配列にデータがコピーされるのでしょうか。  それとも,何らかのポインタだけがrowsオブジェクトがに入って,rows[n]とかしたときに,rowsのメソッドが,を判断してn番目の数字を取得するようになっているのでしょうか。  また,それを確かめる方法(証拠)はありますでしょうか。 また,似たような質問ですが, 1,2,3,4,5,6,7,8,9,10,11,12・・・,9999 というデータから res.split(',')[n] のようにsplitメソッドでn番目を取り出す処理と, すでに配列になっているものからn番目を取り出す処理 rows[n] とでは,どちらの作業が軽い(高速)でしょうか? 感覚的には後者ですが,実際の処理はどうなのかなと

質問者が選んだベストアンサー

  • ベストアンサー
回答No.7

>ANo.6回答 ロード完了時にsplitして配列にしておき、 チェックしたいタイミングでrows[n]するのが最も早いと思います。 (始めに質問されているポインタは関係ありません) > 実はマウスをぐりぐりAjax的に操作して Ajax的にマウスを操作するって、どういう操作でしょうか? ま、「ぐりぐり」で大体わかりますけど。。。 rows=res.split(','); trash=rows[5]; trash=rows[6]; trash=rows[8]; trash=rows[1]; trash=rows[4]; というのと、 trash=res.split(',')[5] trash=res.split(',')[6] trash=res.split(',')[8] trash=res.split(',')[1] trash=res.split(',')[4] というのを比べてみてください。 > また、その読み込み時に配列にコピーする作業に時間がかかるなら、最初からデータをJSONで持ってきてそのまま取り出す方がいいかなと予想しました。ただもし配列への物理的にコピーが無ければJSONにしてもあまり効果は無いかなと思いまして。 JSONといっても、所詮は文字列をevalしますから、 splitしてもevalしても、1回だけの処理ならどちらも時間的には変わらないと思います。 JSONを使うよりは配列で受けた方がわかりやすいかな、と思いますが、 わざわざXMLHttpRequestを使わなくても、<script src="">でいいのでは? ベンチマークの取り方はANo.2やANo.6で出していますから、 適宜ベンチマークを採ってみてください。

ganwan2007
質問者

お礼

ありがとうございます。なるほどevalの処理が意外にかかるのですね。 >、<script src="">でいいのでは? それはサーバー側にコールバック関数を書かせるいわゆるpaddingという方法ですか

ganwan2007
質問者

補足

あ、間違えました。単に最初の読み込み時に取得すればってことですね。実はあるページの中のボタンを押すとこれまで説明した処理が始まるという仕組みなのです。この処理はページ閲覧者の1割くらいしか関係ないので無意味に最初から大量のデータは読み込ませたくないなと。

すると、全ての回答が全文表示されます。

その他の回答 (7)

回答No.8

> それはサーバー側にコールバック関数を書かせるいわゆるpaddingという方法ですか 何か勘違いされてるようですが、 var rows=[1,2,3,4,5,6・・・999]; と書いたファイルをrows.jsという名前で保存して、 HTMLファイルに <script src="rows.js"></script> と書いてください。 evalもsplitもする必要なく、ましてやXMLHttpRequestを使う必要さえもなく、 rowsという配列を利用出来るようになります。

ganwan2007
質問者

お礼

大変参考になりました。 ぜひまたいつかこちらで教えてください。

すると、全ての回答が全文表示されます。
回答No.6

長文すみません。 すみません、文字列の配列へのポインタですから char** rows ですね。 実際は文字列でも関数でも代入出来ますのでchar*でもchar**でもなく構造体へのポインタのようですが。(Firefoxの場合) コピーについてですが、 *説明用に(A)と(B)を追記しています > //(3) > trash=''+str.split(',')[5]; > > //(4) > var buf2=str.split(','); //(A) > trash=''+buf2[5]; //(B) (3)のほうは split(',')したときに、一度メモリ上のどこかに配列を作成し、そこから[5]のみをtrashにコピーします。 split(',')したときに生成される配列はそのままメモリ上から削除されます。 (4)では、 split(',')したときに、一度メモリ上のどこかに配列を作成し、(A)の右辺 その配列のアドレスをbuf2に保存(コピー)します。(A)の左辺 その配列へのポインタ(buf2)が指し示す配列の[5]の内容をtrashにコピーします(B) 、、、と思うのですが、(A)のところはANo.5のように1つ1つやってるのかもしれません。 (4)と(3)に時間差があるのは buf2=配列 の部分の時間です。 (3)はsplit(',')[5]、(2)と(4)はrows[5]になっていますが、 「どのタイミングで配列を生成するか」というのが関係します。 (2)が早い(早く感じる)のは、「初期化(配列を生成する)に必要な時間」を計測していないためです。 初期化の時間を含めると、(2)と(4)は同じ事を行っています。 ganwan2007さんが(2)と(3)を比べられているのか、(2)と(4)や、(3)と(4)を比べられているのかわかりませんが、、、 それとも(1)と(3)や(4)を比べられているのかもしれませんが、、、 (4)よりも(3)の方がいいと思いますが、それ以外は一長一短です。 >ANo.3 お礼 > 文字「,」を見つける作業が必要ですが,配列からn番目を取り出すのはもっとダイレクトな感じがするのですが。。いかがでしょうか > 配列からn番目を取り出すのは >> 配列からn番目をとりだすよりは こういう意味のタイプミスとすると、こういうことでしょうか。 配列を生成せずに、','の位置と出現回数を調べて該当部分だけを取り出しています。 何番目というのが大きな数字になればなるほど遅くなると思います。 (indexOfで前回検索したところから再検索というのができれば早いと思いますが、、、) > 9999兆 このサイズになると配列を生成したときにクラッシュするかもしれませんから、こういう場合はindexOfの方がいいかも。。。でも遅そう。。 var str='1,2,3,4,5,6,7'; var trash,s1,s2,s; s1=new Date().getTime();//ベンチマーク計測開始 for(var bench=0;bench<1000;bench++){//ベンチマーク1000回実行 var p1=0,p2=0; for(var i=0;i<5;i++){  var pbuf=str.indexOf(',',p1);  if(pbuf<0){   p1=pbuf;   break;  }  p1=1+pbuf; } if(p1<0){  trash=''; }else{  p2=str.indexOf(',',p1);  if(p2<0){   trash=str.substr(p1);  }else{   trash=str.substr(p1,p2-p1);  } } }//計測ループ終了 s2=new Date().getTime();//計測終了 alert(s2-s1); 全角スペースでインデントをつけています。

ganwan2007
質問者

お礼

詳しい説明を大変ありがとうございます。ただ私の疑問を予想なさっていることからも、私の言いたい事がうまくいえてないのが分かりました。 まず配列の取り出しの件は、「配列からn番目を取り出すのは」のままで正解です。  何がやりたいかというと、実はマウスをぐりぐりAjax的に操作して、その間に大量のデータをブラウザで処理させたいのです。マウスが1ポイント動くたびに大量データの処理が必要なため、なるべくデータの処理をすばやく終わらそうと。  マウスが動くと、responseTextに入ってきた1,2,3,4…の大量の数列から特定の数字を選んで計算するという処理を1000回繰り返します。現状は、特定の数字を選び出す方法として、res.split(',')[n]を使ってます。つまりres.split(',')[n]が3000回。これが滞る。  そこでresponseTextを取得したときに、いったん配列rowsに全部入れて、res.splitの代わりにrows[n]を使えばもっと早くなるかなと思ったしだいです。  また、その読み込み時に配列にコピーする作業に時間がかかるなら、最初からデータをJSONで持ってきてそのまま取り出す方がいいかなと予想しました。ただもし配列への物理的にコピーが無ければJSONにしてもあまり効果は無いかなと思いまして。

ganwan2007
質問者

補足

少々補足します。 >マウスが動くと、responseTextに入ってきた1,2,3,4…の大量の数列から responseTextにはマウスを動かす前からデータが入っています。 >つまりres.split(',')[n]が3000回。これが滞る。 1000回の間違いです。

すると、全ての回答が全文表示されます。
  • venzou
  • ベストアンサー率71% (311/435)
回答No.5

>ただ,下のtalooさんが書かれているのが(よく理解できてないのですが),talooさんのは「コピーは発生しない」ということをおっしゃっているように感じるので,お二方で答えが違うのかなと悩んでます。 talooさんの答えは「ポインタである」と言う説明で、「コピー」については触れていないように思います。(真相はご本人の回答待ちですが・・・) rowsには、「コピー」されたデータへの「ポインタ」が格納されている、と言うのが正確な表現でしょうか。 res → '1,2,3,4,5,6,7,8,9,10' rows→[0]→ '1'    [1]→ '2'    [2]→ '3'    [3]→ '4'    [4]→ '5'    [5]→ '6'    [6]→ '7'    [7]→ '8'    [8]→ '9'    [9]→ '10' イメージとしてはこんな感じ

すると、全ての回答が全文表示されます。
  • venzou
  • ベストアンサー率71% (311/435)
回答No.4

>後半に関しては,res.splitのほうが「遅い」のではないでしょうか? 肝心な所を書いてませんでしたね(^^; 仰るとおり、res.split(',')[n] の方が遅いと思います。 >res.split(',')[n] >この場合、splitが実行され配列を作成してから、要素を取り出すと思います。(そして配列を捨てる。) この部分は res.split(',')[n]の方が処理が重いことを説明したかったのです。(^^;

ganwan2007
質問者

お礼

ありがとうございます。そこは理解しました

すると、全ての回答が全文表示されます。
  • venzou
  • ベストアンサー率71% (311/435)
回答No.3

>・・・,9999兆 これは多すぎですねw。今のパソコンでは扱えない量です。 ま、それはさておき(^^; >実際に,rows配列にデータがコピーされるのでしょうか。 var res = "1,2,3,4,5,6,7,8,9,10"; var rows = res.split(','); alert(rows[5]); res = "0,0,0,0,0,0,0,0,0,0"; alert(rows[5]); res = ""; alert(rows[5]); rowsがresへの何らかのポインタなら、resを変更すればrowsにも影響が出るはずです。実際は影響ありません。splitの時点で、rows用にメモリが確保され、データはコピーされてますね。 >どちらの作業が軽い(高速)でしょうか? res.split(',')[n] この場合、splitが実行され配列を作成してから、要素を取り出すと思います。(そして配列を捨てる。) 残念ながら、「配列を作成せずに、','をカウントをし、要素を取り出す」みたいな最適化はされないと思いますよ。

ganwan2007
質問者

お礼

ありがとうございます。 前半は理解しました。つまり,実際にコピー(メモリー上で) があるということですよね。 ただ,下のtalooさんが書かれているのが(よく理解できてないのですが),talooさんのは「コピーは発生しない」ということをおっしゃっているように感じるので,お二方で答えが違うのかなと悩んでます。 後半に関しては,res.splitのほうが「遅い」のではないでしょうか? 文字「,」を見つける作業が必要ですが,配列からn番目を取り出すのはもっとダイレクトな感じがするのですが。。いかがでしょうか

すると、全ての回答が全文表示されます。
回答No.2

ポインタという言葉を使われていますが、C/C++はわかりますか? var res='1,2,3,4,5,6,7'; rows = res.split(','); これは char res[14];/* 14とも言い切れないのですが */ char* rows; に相当します。 > また,それを確かめる方法(証拠)はありますでしょうか。 言語仕様です。 JavaScriptでは文字列と数値以外は全てポインタで管理しています。 > また,似たような質問ですが, > すでに配列になっているものからn番目を取り出す処理 splitから作っていても、計測よりも前に配列化(初期化)しておけば基本的に同じ。 昨今のパソコン事情と、同時に多人数が利用するサーバーで動かすわけではありませんから、 よほどの事でない限り、気にする必要はないと思います。 var ary=[1,2,3,4,5,6,7]; var str='1,2,3,4,5,6,7'; var buf=str.split(','); var trash,s1,s2; //(1) s1=new Date().getTime(); for(var i=0;i<10000;i++){ trash=''+ary[5]; } s2=new Date().getTime(); alert(trash+' '+s1+' '+s2); //(2) s1=new Date().getTime(); for(var i=0;i<10000;i++){ trash=''+buf[5]; } s2=new Date().getTime(); alert(trash+' '+s1+' '+s2); //(3) s1=new Date().getTime(); for(var i=0;i<1000;i++){ trash=''+str.split(',')[5]; } s2=new Date().getTime(); alert(trash+' '+s1+' '+s2); //(4) s1=new Date().getTime(); for(var i=0;i<1000;i++){ var buf2=str.split(','); trash=''+buf2[5]; } s2=new Date().getTime(); alert(trash+' '+s1+' '+s2); 参考までにPerlなどではポインタではなく配列の内容全てをコピーしますので、(3)に比べ(4)が圧倒的に遅くなります。

ganwan2007
質問者

お礼

ありがとうございます。C言語のポインタは少しは分かります。使いこなしてません。 ご回答は,つまり, res='1,2,3,4,5,6,7'という文字列に対して rows = res.split(',') としても,結局res[14]と同じなので,どちらも同じ。 split(',')をすると,配列から取り出すときのn番が2n番になるだけなので,つまり,メモリー上で実コピー作業は発生しない。 ということでしょうか。 すみません,よく理解できてません。しかしお書きになられたことは,大事そうなのでなんとか理解したいと思っています。

すると、全ての回答が全文表示されます。
  • VCAT
  • ベストアンサー率20% (16/79)
回答No.1

>実際に,rows配列にデータがコピーされるのでしょうか。 コピーというのをどういう意味で使っているのかしりませんが、 セットですね。 >とでは,どちらの作業が軽い(高速)でしょうか? もちろん後者。手でやってみてもどちらが手間かわかる。

すると、全ての回答が全文表示されます。

関連するQ&A