• ベストアンサー

ソートのテクニックについて

お世話になります。 ソートのテクニックについて教えていただきたく質問しています。 ソートをするに、パタンが二つあると思います。 例示パタン1; 一人が5回の試技を行い、結果を記録したレコードがあり、 5回の試技を昇順に列べてからリストする。 レコード形式;名前、試技1、試技2、、、試技5、試技平均 例示パタン2; 一人が砲丸投げとやり投げを行い、結果を記録したレコードがあり、 砲丸投げと、やり投げ毎に記録の良い順にリストする。 レコード形式;名前、砲丸投げ記録、やり投げ記録 上記パタン1では、データを頭から読み出しながら試技をソートすれば良く、 ソートに要するスペース(メモリ?)は少なくて済む。 パタン2では、予め全レコードについてソートしてからリストする必要があるため、 スペースが要求されると思います。 ここで質問です。 パタン2のような場合、どのようなテクニックを使えばよいのでしょうか。 実際に動かしているのですが、パソコンでは問題なくても携帯電話で動かすと、 ”上限サイズを超えたので云々”とのエラーになります。 (シュワルツ変換というテクニックでソートしています。)   @lines = map {$_->[0]}      sort {$b->[11] <=> $a->[11] or $a->[1] <=> $b->[1]}      map {[$_, split /<>/]} @lines; 上記の場合、メモリに蓄えられてソートがされると思います。 一度外に書き出すようなテクニックの方が良いのでしょうか。 時間も掛からず、メモリも食わない方法が理想ですが、 そうも行かないと思います。 メモリを食わずに済む方法を教えてください。 宜しくお願いします。

  • Perl
  • 回答数5
  • ありがとう数8

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

  • ベストアンサー
  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.2

携帯からのアクセスだからといって、CGIを動作するサーバ側の状況が変わるとは思えないあたりは、回答者1さんと同意見ですが、 とりあえず perl でのソートのメモリ消費量削減について。 Schwartzian transform は、記述はシンプルですが、 ソート中に全データのコピーが発生するため、メモリ効率はあまり高くありません。(回答1のように分けて書いてもメモリ消費は同じです) 配列のインデックスだけをソートする方がメモリ消費量は少なくなります。 それと、各行のsplit後は、ソートに不要なデータを保持しないようにした方がいいでしょう。 そうすると、 --- @key = map { [ (split(/<>/))[0,10] ] } @lines; @lines = @lines[ sort { $key[$b]->[1] <=> $key[$a]->[1] or $key[$a]->[0] <=> $key[$b]->[0] } 0..$#lines ]; --- といったコードになります。 (このコードでも計算量的には Swartzian transformと変わりません)

nagahaha
質問者

お礼

早速有り難うございました。 分からないながらに、お示しいただいたコードを貼り付けてみましたが、 エラーで動きませんでした。 貼り付けミスはないと思います。 全体がよく分かっているわけではありませんが、 keyだけソートするという主旨は分かったつもりです。 最後にある、 0..$#lines ]; の部分が分かりません。 (このまま貼り付けたのではいけないのでしょうか) 宜しくお願いします。

その他の回答 (4)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.5

Perl のスクリプトとしてデバッグする気はありませんか?

参考URL:
http://www.tohoho-web.com/wwwcgi7.htm
nagahaha
質問者

お礼

スクリプトのデバッグ、読みました。 こんなモノがあるのですね、今度やってみます。 というのも、先ほど動かなかったまま全く何もせず、 マシンを代えてみたら動いてしまいました。 原因は分かりません。 ただ、動きはしましたが、やはり携帯電話では最大サイズを超えた旨のエラーで止まってしまいます。 途中までは出ますので、何とか使えます。 有り難うございました。 ということで、 今度動かないようなことが在ればスクリプトのデバッグをやってみたいと思います。 お世話になりました。

  • ralf124c
  • ベストアンサー率52% (232/446)
回答No.4

ご質問に対する回答とはちょっと異なると思いますがエラーとSortの処理とはなんの関係もないように思います。 問題点は処理終了後に出力されるデータ(HTMLでしょうか?)の量が携帯のメモリ容量を超えているためではないかと思います。 携帯のブラウザ表示は少し前までは2kの壁といわれ、コンテンツファイルそのものをトータルで2kバイト以下に抑えないと機種によってはご質問のようなエラーメッセージを吐いて終了という結果になります。 最近では携帯の容量も増えはしましたが、古い携帯を後生大事に使っているやつもいるという可能性と、表示画面の小ささの制約から、一般的に携帯コンテンツはおのずと小さなコードで作るようになっております。 PCで表示させたコンテンツを画像ともどもセーブして、そのファイル容量をチェックし、携帯の限界を確認してみてはどうでしょう。 ソートテクニックに関しては、ソートアルゴリズムが専門ではない(学問の一分野にもなっているくらいなので)のでコメントのしようもありませんが、プログラムは動いてなんぼのものです。 早い、小さい、リソースが少ない、(クールなプログラム)にこした事はありませんが、動かないプログラムはディスクのゴミでしかないのも事実です。 まずは動くものを完成させ、その後にテクを駆使してクールに育ててゆくことをお勧めします。

nagahaha
質問者

お礼

早速有り難うございます。 全く同じデータを使い、シュワルツ変換を使わないで、 かつこれ以上の項目を表示している別プログラムは問題なく動いています。 よって、シュワルツ変換でメモリを食っているのかなと判断したのですが。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.3

その「貼り付けた」というのを, (できれば全部, できなければ関連部分だけでいいので) 示すことはできませんか? またと, 「エラーが出た」というなら「どの行に対しどのようなエラーが出たか」を書くようにしてください (もちろん「エラーが出た行」も示す). そうでないと, 「どこでどのようなエラーが出ているのかを推測する」必要があり, それは回答者に余計な負担を与えるものとなります. @lines = @lines[ sort { $key[$b]->[1] <=> $key[$a]->[1] or $key[$a]->[0] <=> $key[$b]->[0] } 0..$#lines ]; はわけると @sorted_indices = sort { $key[$b]->[1] <=> $key[$a]->[1] or $key[$a]->[0] <=> $key[$b]->[0] } 0..$#lines; @lines = @lines[@sorted_indices]; となります.

nagahaha
質問者

お礼

早速有り難うございます。 質問に書いたとおりですが、     @lines = map {$_->[0]}        sort {$b->[11] <=> $a->[11] or $a->[1] <=> $b->[1]}        map {[$_, split /<>/]} @lines; は問題なく動いていまして、 この部分を教えていただいた下記の分、     @key = map { [ (split(/<>/))[0,10] ] } @lines;     @lines = @lines[ sort { $key[$b]->[1] <=> $key[$a]->[1] or $key[$a]->[0] <=> $key[$b]->[0] } 0..$#lines ]; に置き換えました。 そうしたところ、 cgi自体がエラーとなって動かなかったということです。 中に入っていないので、どの行とかになりません。 この内容で答えになりますでしょうか。 宜しくお願いします。

  • zxcv0000
  • ベストアンサー率56% (111/196)
回答No.1

# split /<>/ と $a->[11] のからみが不明ですが、本題で無さそうなので気にしない事にします。 ============================== 同じ CGI を同じ条件で閲覧したとき、PC と 携帯で CGI の正常/異常が変るのは考え難いと思います。 ・使用したデータは同じですか? ・ブラウザ等の性質によって処理を振り分ける部分はありませんか? ・さらには、JavaScript では無く CGI のエラーってのは確かですか? ============================== ご質問の件ですが、 map(sort(map())) とネストさせるとそれぞれの段階で無名配列がとられるかも知れません。 Perl が最適化で頑張ってくれれば良いのですが、そうで無ければ以下の様にステップを分けた方がメモリ使用は減ると思います。 @lines = map {[$_, split /<>/]} @lines; @lines = sort {$b->[11] <=> $a->[11] or $a->[1] <=> $b->[1]} @lines; @lines = map {$_->[0]} @lines; まず sort の内部で split という高負荷処理をさせない、次にメモリ使用を減らすという考え方は、良いと思いますよ。 極めたいなら、Perl の sort() を使用せずに自分で書く手があります。 クイックソート・ラディックスソート・ヒストグラムソート とか、いろいろの手法からデータ傾向に合うものを選び、小メモリ化に腐心すれば良い結果が得られる*かも*知れません。            

nagahaha
質問者

お礼

早速有り難うございます。 ># split /<>/ と $a->[11] のからみが不明ですが、 済みません、私のコードをそのまま貼り付けました。 > CGI の正常/異常が変るのは考え難いと思います。 メモリ消費量等は変わらないかも知れませんが、 携帯電話では豊富にメモリが使えないのではと思っています。 お示しいただいたコーディングにしてみましたが、 (もちろん正しく動作しましたが) 携帯電話での結果は同じ、「上限サイズに云々」が出ました。 >Perl の sort() を使用せずに自分で書く手があります。 全くの素人で、例示いただいたコードを何とかアレンジして 試行錯誤すると言ったレベルです。 今後、勉強が必要です。

関連するQ&A

  • 任意な項目のソート

    お世話になります。 なかなか説明自体が難しいのですが、 以下のようなファイルを読み、リストしたいのですが、 単純にリストするのではなく、ソートして並べ替えてからリストが必要です。 ファイル構成は、 名前<>所持金<>限度額<>最終異動日<> のような属性で、 (1)山田太郎<>120000<>200000<>080501<> (2)林佳子<>32500<>100000<>080429<> (3)浪速義郎<>257000<>300000<>080322<> (4)、、、、 のように入っています。 ((1)、(2)、(3)、、はレコードです。) リストは、 例えば、 あ:限度額の降順 い:最終異動日の昇順 等と指示されます。 例えば、 上記『あ』の例(限度額の降順)で教えていただけないでしょうか。 期待する結果は、 (3)浪速義郎<>257000<>300000<>080322<> (1)山田太郎<>120000<>200000<>080501<> (2)林佳子<>32500<>100000<>080429<> (4)、、、、 となれば良いのです。 ちなみに単純に読み込んだままでリストの時には以下のように書いています。 open(IN,"$file") || &error("Can't open $file"); @lines = <IN>; close(IN); foreach $line (@lines) {     local($trm01,$trm02,$trm03,$trm04) = split(/<>/,$line); 宜しくお願いします。

    • ベストアンサー
    • Perl
  • Javaプログラム内でソートすべきか悩んでいます。

    Javaプログラム内でソートすべきか悩んでいます。 開発環境は j2sdk1.4.2 eclipse3.2.0 Oracle10g(ドライバはThin接続) です。 処理の大まかな流れは以下の通りです。 1. 社員番号リスト(100,000件)を読み込む。(txtファイルで社員番号の順番はソートされていない) 2. 次の3で検索を行うために社員番号を1000件単位でリスト化する。 例:下記のような文字列を作成し、ArrayListに入れる   ('000077','0100002','0000503',~,'0080400') 以下の処理は2で作成したArrayListの件数繰り返す 3. データベース検索を行う。 社員番号を検索キーに検索を行う。(2で作成した文字列を 社員番号 in 「文字列」のような形で) 4. 検索結果(1レコードにつき20項目)をファイルへ出力する。(CSVファイルへ結果を追記していく) 4で結果を出力するのですが、ソート条件が決められています。 条件は「住所コードの昇順」、「社員番号の昇順」です。 住所コードはDB内のデータにあります。 3の検索結果をメモリに蓄積して全件取得を終えたらソートしようと思いましたが、 OutOfMemoryエラーが発生してしまいました。 ひとつ案を考え、2の処理を終えたあとにDBから住所コードと社員番号を取得して TreeMapに全件を蓄積(キーは「住所コード + 社員番号」、データは社員番号)し、 (このデータでOutOfMemoryエラーは発生しませんでした) 自動的にソートされた社員番号で再度2~4の処理を行うのですが すごく処理時間が増えてしまい効率が悪い気がします…。 処理時間の短縮、メモリ使用の抑制を考慮した良い案はないでしょうか?

    • ベストアンサー
    • Java
  • ロンドン五輪メダル期待してますが・・・?

    先日あった韓国テグの世界陸上ではハンマー投げの 室伏選手が見事金メダル獲得!また、なでしこジャパン が見事ワールドカップ優勝かつロンドン五輪出場権を アジアトップで獲得!・・・とここまでは大変喜ばしいの ですが、それ以外の話になると非常に悲しくなってきます。 日本の陸上といえばマラソン。しかしここ最近アフリカ勢の 驚異的なスピードに完全に圧倒されていますよね。また 中距離・短距離では女子の福島選手などは有望かと 思いますが・・・それ以外にはちょっとなかなか。また、 その他のやり投げや砲丸投げや円盤投げや走り幅跳び 走り高飛び・・・などの競技ではほとんど五輪予選通過 記録に満たなかったり、満たしても予選通過できずなど 非常に残念です。陸上以外でも柔道やテニスなども 思わしくないですよね~。前ふりが長くなり恐縮です。 さて質問ですが、なぜここ最近オリンピックでメダル 獲得ができそうな選手が少なくなってしまったのでしょうか? ここ最近ではなく昔からでしょうか? 一部の(フィギュアスケートなど)競技は強化がうまく 行っているようですがそれ以外の競技は強化がうまく 行っていないからでしょうか!?素朴な疑問です。

  • アクセスカウンター

    PHPで各ファイルへのアクセス数等を1つのファイルに行単位で記録するように作っております。 (1)各ファイルへのアクセス数をcount.datファイルに書き込む  ※書き込み内容:(ファイル名,日付,合計,今日,昨日,リモートアドレス) (2)該当ファイルのデータがない時は新規に追加。ある時はデータ更新 (3)新規に追加された場合はファイル名部分で行単位でソートする。 【ファイルの内容例】 abc.php,08/12/13,10,6,4,ocn.ne.jp def.php,08/12/13,10,6,4,ocn.ne.jp ghi.php,08/12/13,10,6,4,ocn.ne.jp 【現象】 (1)については元々ファイル単位で個別ファイルに記録させていた処理をもってきたものなので特に問題ないですが、(2)のところで躓いてます。 最初は該当ファイル名が無いので新規追加するだけなので問題ありません。2回目以降は該当ファイルがあるのでそのデータの更新ですが、最終行とその1つ前の行の間にスペース行が出来、その後はアクセスの度にその間のスペース行が増えていきます。 【ソース例】 //$countFile:書き込みファイル $lines = file($countFile); $dataLine = count($lines); for($i=0; $i<$dataLine; $i++) { //該当ファイル名データがある場合は以下の処理を行う(省略) $lines[$i] = trim($lines[$i]); $today++; $count++; $lines[$i]= "$fileId,$date,$count,$today,$yesterday,$host"; $fp = fopen($countFile,"w"); flock($fp, LOCK_EX); rewind($fp); fwrite($fp, rtrim(implode("\n", $lines),"\n")); flock($fp, LOCK_UN); fclose($fp);   break; } 色々試行錯誤しながらやってますが解決できません。どの部分が悪いのかご教授お願いします。またソートの部分も教えていただけると助かります。

    • ベストアンサー
    • PHP
  • ファイルメーカーによるリストの作成法を教えて下さい

     FileMaker Pro 7で作成したデータベースの一定条件を満たすレコードの特定のフィールドをリスト形式で表示させるにはどうしたらよいでしょうか。  ニュース記事1本を、1レコードに収め、日付、見だし、リード、本文をそれぞれ別のフィールドに記録、電子、運輸機器、化学等の業種を分類するためのフィールドも設けました。  例えば、電子関連の記事を検索、日付順にソートして、『日付/見だし/リード』のみのリストをモニター上に表示させるにはどうしたらよいでしょうか。  試みに『日付/見だし/リード』のみのレーアウトを作成、上記の検索を実行、『リスト形式』を選択したところ、最初の記事1本のみの『日付/見だし/リード』が上部に表示されました。スクロール・バーで下方に画面をスクロールさせたところ、他の記事の『見だし』や『リード』がバラバラに現れましが、整然としたリストとしては表示されませんでした。

  • 掲示板のソートテクニックについて

    やりたいことは、PostgreSQL上にあるBBSテーブルの ・カラム「更新日付」の降順で親記事をソート ・カラム「返信順番」の昇順で子記事をソート して表示したいのですが、 どのようなロジックにすれば良いでしょうか? order by 更新日付 まではできたのですが、SQLだけではできそうに ありません。PHPでどのようにソートすれば できますでしょうか? ◆BBS出力イメージ 親2  子 1 2 3 親1  子 1  子 2

    • 締切済み
    • PHP
  • 至急! C言語 DxLib.h コンパイルは通る

    はじめまして。 今,C言語でゲームを作っています。そのためにDxLib.hを使います。初心者です。 それで画面スクロールを作ったのですがぜんぜん動きません。 このファイルにプログラムを記しています。 http://loda.jp/0tm/?id=1431 プログラムの内容としては,まず,2次元の配列でマップをつくり(たとえば平原は00,森は1などと決めておいて),次にgame_pattern.bmpという画像ファイル(いわゆるパターン画像です)をメモリ上に記録して,DrawRectGraphで,画面の左上から順にマップを描画していくというつくりです。 実際の症状としては,コンパイルは通るのですが画面は真っ黒のままで,何も起こりません。 かといってフリーズもしないです。 環境ですが,いろんなホームページのサンプルプログラムなどは動くので大丈夫だと思います。 当方初心者です。プログラムもはっきり言って汚いと思いますが,どこが原因で何も表示されないのか教えていただければ幸いです。

  • リストビュー ⇔ 別ファイル構造体 の実現方法

    VC++6.0、Win32 APIを用いて作成しているダイアログボックスを表示するアプリについてです。 パターン(パターン1~3までの3種類)が格納される列と、文字列(最大256バイト)が 格納される列の2列からなるリストビューがあります。 そのリストビューに新しい情報(行)を追加するたびに、その該当行の情報を 別ファイル(設定ファイル)の構造体に格納し、リストビューの変更・削除があれば、 その都度構造体を更新し(?)反映させたいです。 メモリも無駄なく、効率的に使いたいです。 また次回以降そのアプリを起動させる際には、設定ファイルの内容を読み込んでリストビュー の表示に反映させたいです。 正直、構造体は苦手なため解らないことだらけなのですが、パターンを格納するint型の変数と 文字列を格納する固定長256byteのchar型配列の変数が必要なのではと思っています。 後は、レコード数を格納するヘッダーも必要なのでしょうか・・・ メモリの取得、開放、移動方法はいまいち分かりません。 現在は、ラジオボタン(パターン用)とエディットボックス(文字列用)を用いて、 リストビューに登録するところまでは出来ています。 変更や削除の機能も実装出来ています。 上記の処理を実現させるための詳細な流れを教えてください。 サンプルコードも載せて頂けると幸いです。 分かりにくい文章で申し訳ありませんが、よろしくお願い致します。

  • テクニック

    潮を噴かすにはどうしたらよいのですか? 

  • 彼を振り向かせるテクニック

    今晩は!! 以前「 上司に片思い 」で質問した者です。 彼は 同い年の 31才。 立場は店長 中学生の様にからかってきたり、下ネタをバンバンいってきたりするタイプ。 私は完全に いじられ。 いじめられ??キャラになってしまっています  (;■;) 気分やさんで 機嫌のいい時は よく話しかけてくる。 不機嫌な時は 距離を置いてくる人です。 そんな 彼が 好きなんですが。。。。。。 こんな関係の状態で 彼を振り向かせるにはどうしたら良いでしょうか???? ★★ 男性の方 ★★ からかいの対象の相手を 好きになったり 女性として見る様になる 行動や、言動。 しぐさを 教えて下さい。 ★★ 女性の方 ★★ 振り向かせた行動 テクニックを教えて下さい。

専門家に質問してみよう