- ベストアンサー
数字のソート方法とは?
- 数字のソート方法について教えてください。
- 連番を崩さずに昇順に数字を並び替える方法を教えてください。
- 具体的なデータを使って数字のソート方法を教えてください。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
解決しましたか。よかったです。 ポイントですか。 具体的に何のポイントなのか、何を教えてほしいのかがちょっと分からないのですが・・・ コーディングする際の注意点などでしょうか。 とりあえず注意点、というか私がいつも考えていることは、いくつかに分けて考えることです。 あと常に一箇所に集中することです。 全体を見ず、現在の部分で何をやればいいのかということを考えて、必要な処理だけを書いていきます。 余談で、LinuxとかOSのソースコードは1000万行以上あるらしいので全て見ることは現実的に不可能に近い訳ですが。。。 http://slashdot.jp/linux/article.pl?sid=08/10/24/114203 それと、シュワルツ変換というものを知らなかったので調べてみたところ次のページを見つけました。 (Perlの例が載っててよかった。。。) http://www.wdic.org/w/TECH/%E3%82%B7%E3%83%A5%E3%83%AF%E3%83%AB%E3%83%84%E5%A4%89%E6%8F%9B これによると ------------------------------------ リストを、各要素に一定の演算を施したもので操作したいが、 最終的に必要なのが演算の結果ではなく、本来の要素である場合に用いる手法。 ------------------------------------ らしいので少なくともソートではないです(間違っていたらすみません)。 どうやって昇順(あるいは降順)に並べるか、という「ソートの手法(アルゴリズム)」ではなく、 上記のような状況に対する「コーディングの手法」みたいなもので、ソートは上記の文で言う「一定の演算」という部分にすぎません。 このページの例では、大文字小文字の区別をつけずにソートしたいが、 結果として表示するものは元の文字列にしたいというものです(結果がすべて大文字や小文字になっていたら変ですよね)。 そしてそれを実現するために、このコードでは 1. ソートする配列の要素を「元の文字列」とソートに必要な「全て小文字にした文字列」を要素にもつ「配列のリファレンス(ポインタのようなもの)」にして(一つにまとめる)、 ------------------------------------ map { [ $_, lc($_) ] } @unsorted ------------------------------------ 2. 大文字小文字の違いを無視するために、「全て小文字にした文字列」で比較し、ソートする ------------------------------------ sort { $a->[1] cmp $b->[1] } ------------------------------------ 3. ソートされた結果の「元の文字列」を取りだす ------------------------------------ map { $_->[0] } ------------------------------------ というようなことをしているようです。
その他の回答 (4)
- kirikirkaz
- ベストアンサー率60% (21/35)
2つ質問をさせてください。 まず最初に質問者さんは 連番<>数字1<>数字2<>数字3<>数字4<> のような行をソートしたいと仰いましたが実際は 連番<>数字1<>数字2<>数字3<>数字4<>数字5<>日付 のような行が続いているということでしょうか? それでソートしたいのは 数字1<>数字2<>数字3<>数字4<>数字5 の部分ということでよろしいでしょうか? 次に解決につながるかもしれないアドバイスなのですが、 Perlでは -------------------------------- sort { $a <=> $b } @trm23456 -------------------------------- これだけでは、@trm23456の値は変わりません。 @trm23456の値を変更するには、 -------------------------------- @trm23456 = sort { $a <=> $b } @trm23456 -------------------------------- と「ソートした結果」を再び代入する必要があります。 もし現状が「ソートしたつもりなのに、ソートされていない」という状態なのであれば、これで解決するかもしれません。
お礼
kirikirikaz様、 大変お手間を取らせております。 お陰様で解決しました。 まさにご指摘のとおりでございまして。 結果がソートされていると思いこんでおりましたので、 代入を無視しておりました。 また、質問と実際が違うのも申し訳在りませんでした。 (ご指摘1はそのとおりでございます。) 実際を書いても大変なので、 内容が違わないエッセンスだけ書かしていただきました。 (何時も要点が分かれば一から自分でコーディングしております) 今回の件は、 過去にシュワルツ変換というソートを勉強した折り、 @lines(今回の@trm23456)を予めソートしていたので、同じと勝手に思いこんでしまったモノです。 折角ここまで教えていただいたので、 トコトンと言うことで今少しお付き合いいただければ幸いです。 今回の例Aは、 データの中に例えば5回くじを引いた結果があり、 それを見やすくするために昇順に並べたという考え、 よってレコード(行)の順番は不変。 前回の例Bは、 例えば、徒競走と砲丸投げをやって個人毎に2つの結果があった場合、 徒競走の順位で表示したり、砲丸投げの順位で表示したりと、 レコードの順番が変わってしまうケースの違いなのですね。 そして今回教えていただいたのはAのケース、 シュワルツ変換を習ったのがBのケース。 格好は似ていますが、ここら辺について、 ポイントが聞ければ大変嬉しく思います。 これだけ教えていただいて厚かましいのですが、 お暇なときに宜しくお願いいたします。 もう解決したのですが、その後に本件をクローズいたします。 宜しくお願いします。 有り難うございました。
- kirikirkaz
- ベストアンサー率60% (21/35)
「1件」というのは「1行」のことでしょうか?「1つのファイル」のことでしょうか? それとも質問の冒頭でレコードと仰っているのでデータベースのことでしょうか? (私はデータベースは扱ったことがないのでもしそうだったら解答できない可能性がありますが。。。) あと分かっていたらすいませんが、DATAは__DATA__以下にあるテキストを読み込むものなので、 DATAの部分をもし標準入力でしたらSTDIN、またはオープンしたファイルに差し替える必要があります。
お礼
お世話になります。 何回も恐縮です。 まず、データはexcelで出力したモノで、シーケンシャルファイルです。 1行が(質問では、はしょりましたが)連番、5個の数字、日付で構成されています。 この構成のレコード(行)が複数行在ります。 open(IN,"$file"); @lines = <IN>; close(IN); で読み、 foreach $line (@lines) { local($trm01,$trm02,$trm03,$trm04,$trm05,$trm06,$trm07) = split(/<>/,$line); #連番、数字1、2、3、4、5、日付 と在って、 ここから$trm01~$trm05をソートしたかったのです。 それで教わった形を以下のようにしています。 @trm23456 = ($trm02,$trm03,$trm04,$trm05,$trm06); #配列を作りたい sort { $a <=> $b } @trm23456; #ソートしたい そして分からないので書けていませんが、 最終的には、@trm23456でソートした結果を、 また元の$trm02~$trm06に戻したいのです。 これが出来れば完成なのですが。 全く分からないで書いているので、頓珍漢と思いますが、 手が入れられるでしょうか。 お手数をおかけしますが、宜しくお願いいたします。
- kirikirkaz
- ベストアンサー率60% (21/35)
そうでしたか。学ぶ気のある人にいきなり解答を示す、誠意を愚弄するようなことをしてしまってすみません。 DATAは、開かれた入力ファイルと同じです。 DATAから読み込む(<DATA>)ことで __DATA__(または__END__)の下に貼り付けられたテキストをあたかも「入力用ファイル」として読み込むことができる便利なものです。 ------------------------- while (<DATA>) { ------------------------- まずこの行でDATAから1行だけ、$_という変数に読み込んでいます。 この$_という変数はPerlのソースの至る所で使われます(変数を指定しない場合にこの変数に入ることが多い) 明示的に読み込む変数を指定する場合は ------------------------- while (defined(my $line = <DATA>)) { ------------------------- と書くと$lineに1行だけDATAから読み込まれます。 myは(スコープを限定する)変数宣言の一種です。 もっとPerlを詳しく知りたくなったら調べてみてください。 そうして読み込んだ文字列を次の行によって、末尾の改行を削除しています。 ------------------------- chomp; ------------------------- これは ------------------------- chomp $_; ------------------------- と同じです。 引数が省略されるとこの変数が使われます(全部の関数でそうなるというわけではありませんが・・・) そして次の ------------------------- my ($renban, @nums) = split /<>/; ------------------------- は ------------------------- my ($renban, @nums) = split /<>/, $_; ------------------------- と同じです。 これによってsplitで$_の文字列を"<>"というセパレータで配列に分割しています。 そしてその配列の1番目を$renbanに、残りの配列(2,3,4,5番目)を@numsという配列に代入しています。 最後の ------------------------- print join('<>', ($renban, sort { $a <=> $b } @nums)) . "<>\n"; ------------------------- この行はいろんな処理を一度にしているのでいくつかに分けると ------------------------- sort { $a <=> $b } @nums; ------------------------- の部分で@numsを「数値」としてソートしています。 普通に ------------------------- sort @nums ------------------------- とすると「文字列」としてソートされてしまうので 1から10の配列が1, 10, 2, 3, ...とソートされてしまうなど不都合が起きてしまいます。 そうしてソートされた配列を ------------------------- join('<>', 配列) ------------------------- という部分で繋げて1つの文字列にします。 そうしてできた文字列の後ろに出力の結果を整えるため"<>\n"をくっつけて ------------------------- print 文字列 . "<>\n" ------------------------- としているわけです。 この動作をwhileによって1行ずつ行った結果、質問者さんの意図した結果になる、というわけです。 説明下手で所々説明を省いたので伝わるかどうか。。。
お礼
kirikirikaz様、 何回も有り難うございます。 さらに手取り足取り、嬉しいです。 書いていただいたことは全て目から鱗です。 そして分かったつもりでやってみましたがダメでした。 そっくりコピーしてもダメなのでしょうか。 (勿論全角の部分は半角スペースに置き換えましたが) また、私のロジックは現状1件ずつ読み込んで処理しています。 教わったことを租借しながら私のロジックに当てはめてやってみます。 たどたどしく進んでいるため、次のお礼は何時になるやら分かりませんし、 また質問させていただくかも知れませんが、 宜しくお願いします。 (明日になってしまうかも知れません) お世話になります。 どうも有り難うございました。
- kirikirkaz
- ベストアンサー率60% (21/35)
こういう時はセパレータ(区切り文字)で区切ってから操作(この場合はソート)するとやりやすいです --------------------------------- #!/usr/bin/env perl use strict; use warnings; while (<DATA>) { chomp; my ($renban, @nums) = split /<>/; print join('<>', ($renban, sort { $a <=> $b } @nums)) . "<>\n"; } __DATA__ 1<>8<>13<>27<>30<> 2<>20<>9<>1<>16<> 3<>5<>31<>36<>38<> 4<>52<>79<>18<>27<> 5<>23<>15<>9<>28<> 6<>38<>6<>45<>25<> ---------------------------------
お礼
早速有り難うございます。 教えていただいたのですが、基本が分かっておらず、 質問させてください。 DATA,$renban,@numsはそれぞれ何を指すのでしょうか。 DATAはレコードの名前を書けばよいのでしょうか。 $renbanと@numsはこのまま書いておけばよいのでしょうか。 説明いただければ嬉しいです。 宜しくお願いします。
お礼
kirikirikaz様、 またまた詳しく、さらに調べていただいてまで説明いただき、 有り難うございました。 シュワルツ変換はソートの例として出ていたので、 てっきりそうかなと思いましたが、勉強しなければいけないですね。 mapの目的も分かりました。 聞きたかったのは、 1レコードの中をソートするのと、 レコード自体をソートするのとでは、 書き方でどう違うのかというポイントでしたが、 シュワルツ変換はソートではないということで、 自分なりに研究してみます。 (前者は単純sortを、後者はシュワルツ変換を使うのかなと思っていました。) とにかく今はちゃんと動いております。 大変お世話になりました。 今後とも宜しくお願いいたします。 20点では申し訳在りませんが、それしか付けられないので。 有り難うございました。