• ベストアンサー

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

今,単純に「,」で区切られたデータが大量に続くテキストファイルがあっとします。(もちろん有限ですが) 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

  • 配列の並べ替えのやりかたを教えてください

    適当に 5,1,3,2,4,6 と書かれたテキストがあるとして、 これらの数字を大きい順に並べかえるにはどう 記述すればいいか教えていただけないでしょうか? もともとの並びから任意の数字を参照するところまでは わかりました。よろしくお願いします。 ================================================================ loadLV = new LoadVars(); //LoadVarsオブジェクトを作成 ranking=Array //配列を用意 loadLV.onData = function(data){ ranking = data.split(","); //コンマ区切りでデータを配列 trace("「" + ranking[0] + "」"); //5が出力されます }; loadLV.load("ranking.txt"); //テキストの読み込み

    • ベストアンサー
    • Flash
  • sendRequestのcallback

    以前に「プルダウンメニューの利用」で質問させてもらった者です。 Ajaxを使ってのPHPとの連携のため、sendRequestを使用しました。以下がJavaScriptになります。 function test(oj) { sendRequest( on_loaded1, //コールバック関数 'data='+oj.value, //データ 'GET', // HTTPメソッド 'net.php', //URL true, //非同期 true //強制ロード ) } net.phpにデータを送信し、計算をします。 net.phpからはreturnで以下のような配列を返します。 return $array($RaD, $RaM, $RaS, $DecD, $DecM); 返還された値をcallback関数、以下のような関数で受け取っています。 function on_loaded1(oj){ var res = new Array(); res["RaD","RaM","RaS","DecD","DecM"] = oj.responseText document.forms["atai"].elements["RaD"].value = res alert(res); } しかし、alertには何も表示されないため、値が帰ってきていません。 callback関数の使い方がいまいち判らないので、ご教授いただければと 思い質問させていただきました。 よろしくお願いします。

  • VBAの配列の質問です

    こんにちは、VBAについての質問です。 配列について3点ほど質問致します。 ・ フォームに貼り付けた、ラベル、テキストボックス、コンボボックスの名前を配列にして、その数自体も変数にして (上記のコントロールの数は当然分かっているのですが敢えて変数名でとりたいのです)、配列のデーターとして入れて やることは可能なのでしょうか。   特に疑問なのは、テキストボックス、コンボボックスには「文字型」、「数字型」が有ります。その場合の配列の型 はどのように宣言してやる のでしょうか。 ・ 仮に上記が可能ならば、特に疑問なのは「数字型」は「数字型」として、セルには記入されるのでしょうか。   それとも、数字の場合には、セルへの入力時とか、セルからの出力時とかに、キャスト等で型変換等の処理が必要になる のでしょうか。 ・ またそれとは別の配列として、テキストボックス、コンボボックスのデーターだけを配列データーとして入れてやるのは 可能なのでしょうか。

  • どうすればresponseText結果を配列に格納できますか?

    どうすればresponseText結果を配列に格納できますか? javascript初心者同然のものです。 今サーバー上にあるテキストファイル(10列*4行)をjavascriptで読み込み、各行を異なる一次配列に格納したいと思ってますが、。 例えば以下のように構成できればと思います。 function loadTextFile() { httpObj = createXMLHttpRequest(storeData); if (httpObj) { httpObj.open("GET", path, true); httpObj.send(null); } } // 読み込んだファイルを格納 function storeData() { if ((httpObj.readyState == 4) && (httpObj.status == 200)) { var result = httpObj.responsetext.split("\t"); ---> ここにループで配列に格納したい } }

  • perlでの三次元配列の作り方

    perlで三次元配列をテキスト入力から作りたいのですが、例えば二次元配列の場合 foreach $line (@input) push @data, [split /[:]/, $line]; で@dataが二次元配列になるのですが、三次元配列の場合このあとに push @output, \@data; とするとリファレンスが同じであるためループをまわしてもうまく三次元になりませんよね。 解決法はありますでしょうか?

  • C# 配列の配列(多次元配列?)

    C#において、配列の配列中に格納した値を、検索することを 行いたいのですが、格納した値そのものを見ることができません。 まだ、C#を始めて間もないので、配列に格納する時点で、 不備があるかも知れませんが、お願いします。 やりたいこと ・テキストファイル内にある値を、2次元配列または、多次元配列に格納 ・配列に格納した値で、データチェックなどを行う予定  テキストファイル内のデータは、下記内容となり要素数も固定ではなく変動する   A=1,2,3・・・   B=11,22,33・・・ 実際のソースは、 //配列 ArrayList list = new ArrayList(); //配列格納 1レコード毎用 ArrayList listtmp = new ArrayList(); while ((strGenderTextLine = objReader.ReadLine()) != null) {  string strBuffer;  //「=」前の値格納用変数  string[] strBuffer2; //「=」後の値格納用配列  listtmp=null;  //strtmpに「=」前の値を格納  strtmp = TextLine.Split('=').GetValue(0).ToString();  //strtmp2に「=」後の値を格納(配列)  strtmp2 = TextLine.Split('=').GetValue(1).ToString().Split(',');  for (int i = 0; i <= strtmp2.Length - 1; i ++)  {   //[i,0]に、「=」前の値を代入   if (i == 0)   {   listtmp.Add(strtmp);   }   else   {   listtmp.Add(strtmp2[i].ToString());   }  }  //list配列にlistTmp配列を格納(配列の配列)  list.Add(listtmp);  intT = intT + strtmp2.Length;  //行数カウント  intTLine = intTLine + 1;  } ここから、配列「list」内に入っている値を閲覧することができる方法を教えていただければと思います。 宜しくお願いいたします。

  • オブジェクトから二次元配列へ指定条件下で変換したい

    下記「元データ」から、やりたいことに基づき、「結果データ」を取得するにはどうすればよいでしょうか? ■元データ(オブジェクト) { "0":["東京","1","n1"], "1":["大阪","2","n2"], "2":["京都","3","n3"], "3":["福岡","4","n4"], "4":["東京","5","n5"], "5":["東京","7","n6"], "6":["大阪","1","n7"] } ■やりたいこと 1.「配列0番目の値」で名寄せ 2.「配列1番目の値」の合計数を、新たな配列1番目に配置 3.「配列1番目の値」の重複カウント数を、新たな配列2番目に配置 ■結果データ(配列) [ ['東京',13,'3'], ['大阪',3,'2'], ['京都',3,'1'], ['福岡',4,'1'] ]; ------------------------------------------------------------------------------ また、元データが配列だった場合、同じ結果を求めるのはどうすれば良いでしょうか? ■元データ [ ['東京',1,'n1'], ['大阪',2,'n2'], ['京都',3,'n3'], ['福岡',4,'n4'] ['東京',5,'n5'] ['東京',7,'n6'] ['大阪',1,'n7'] ];

  • PHPでfile()を使った際の配列の要素について

    PHPのfile関数の動作について質問させて頂きます。 テキストファイルからfile()を使って配列に各行のデータを取り込んだのですが、その配列から特定の要素を探そうとしたところ、検出できませんでした。 テキスト.txtの内容------- AAA BBB CCC --------------- $array = file("テキスト.txt"); $word = "AAA"; $keys = array_keys($array,$word); var_dump($keys); 簡略化しましたが、こんな感じで実行するとAAAが格納されているはずの[0]番目のkeyは検出されません。 bar_dumpを使って$array[0]と$wordを確認してみたところ、以下のようなデータが帰ってきました。 $array[0] → string(5) "AAA" $word → string(3) "AAA" まったく同じ文字列なのに、配列の方の長さが2ほど大きくなっています。 そこでtrimを使用してみたところ、配列からこの謎の2バイト?のデータが削除できました。 検索も正しく動作するようになりました。 文末に改行が入ってるのかとも思ったのですが、\nを削除する処理では検索が出来なかったので、不思議に思っております。 テキストファイルから取り込んだ際に、文字列の前か後ろに何らかの文字が入っているのだと思うのですが、実際どのような文字が入っているのでしょうか? ---------------------------------- それともう一つお聞きしたいのですが、 テキストファイル内容がある程度長い(100行以上、または1万文字以上など)場合、file()で配列にデータを取り込むのは負荷が大きかったりするのでしょうか? fgetsで1行ずつ取り出して比較する方法も考えたのですが、処理の繰り返しと取り込むデータの大きさのどちらに配慮するべきか悩んでいます。 もし100行や1万文字が多い・少ないという感覚になる場合、実際「配列にするには大きすぎる」という感覚はどれくらいの容量から考えるべきでしょうか? 後半の質問につきましては明確な答えで無くても、「自分はこう感じる」というような感覚的なご意見でもお聞きしたいと思っています。 お手数をおかけしますが、どうぞよろしくお願い致します。

    • ベストアンサー
    • PHP
  • 2次元配列を部分的に削除する方法

    VBAで配列のデータを部分的に削除してその削除した後のデータを前に詰めたいのです 配列のデータ 001 X 002 Y ←この行を削除した配列にしたい 003 Z 削除後の配列データ 001 X 003 Z こんなイメージなのですが、配列の削除して前につめるという処理はどのように すればいいでしょうか? 1行で実現できるような配列処理用のメソッドがあるのでしょうか? 2次元配列を行削除して前につめる処理なのですがアドバイス下さい

  • データの抽出、配列操作で教えて下さい。

    こんばんは、お世話になります。 配列操作で教えて頂きたく。 次のデータをuser.datとします。 1<>yamada<>99999<> 2<>tanaka<>22222<> 3<>suzuki<>10101<> 4<>yamada<>12345<> 5<>yamada<>55555<> user.datの中からyamadaの行だけ取り出して 3番目の数字データでソート表示したいのですが なかなかうまくいきません。 open(F,"user.dat"); @load_txt = <F>; close(F); foreach $data (@load_txt){ if((split(/<>/,$data)[2]) eq "$usid"){push(@txt_lines,$data);} } @txt_lines = sort{(split(/<>/,$a))[2] <=> (split(/<>/,$b))[2]}@txt_lines; 上記でおかしな所ありましたらご教示頂きたく 宜しくお願いします。

    • ベストアンサー
    • Perl

専門家に質問してみよう