- ベストアンサー
シュワルツ変換の不具合
シュワルツ変換の不具合で困っています。 http://oshiete1.goo.ne.jp/kotaeru.php3?q=1959574 http://oshiete1.goo.ne.jp/kotaeru.php3?q=1882190 で質問したものです。 #!/usr/local/bin/perl print "Content-type: text/html\n\n"; &hoge; sub hoge{ open(o,"hoge.txt"); @all = <o>; close(o); for (@all){ ($sentence,$filename) = split(/,/,$_); $score++; push @hoge, ($score,$_,"<br>\n"); } @hoge = map {$_->[0]} sort {$b->[1] <=> $a->[1]} map {[$_, split /,/]}@hoge; print @hoge; } というcgiを作成し、実行してみたのですが望んだ処理が出来ません。 hoge.txtは ,123,abc.txt ,456,def.txt ,789,ghi.txt ,123,jkl.txt ,456,mno.txt ,789,pqr.txt という内容です。 cgiを実行すると 6 5 4 3 2 1 ,789,pqr.txt ,456,mno.txt ,123,jkl.txt ,789,ghi.txt ,456,def.txt ,123,abc.txt となってしまいスコアが先頭に集まってしまいます。 シュワルツ変換の行を削除すると 6,789,pqr.txt 5,456,mno.txt 4,123,jkl.txt 3,789,ghi.txt 2,456,def.txt 1,123,abc.txt こうなるのですが、これをシュワルツ変換を用いて 1,123,abc.txt 2,456,def.txt 3,789,ghi.txt 4,123,jkl.txt 5,456,mno.txt 6,789,pqr.txt と出力させたいのです。 どこをどのように変えればよいでしょうか。 宜しくお願いします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
チェックすべき点が2つあります。 push @hoge ... の結果、@hogeにはどういうデータが入っていますか? 期待通りのデータ構造では入っていないはずです。 最初のmapを適用した結果はどういうデータ構造になっているか把握していますか? こういうときは、標準モジュールの Data::Dumper を使って、データ構造をチェックしましょう。 また、オープンするファイルハンドルに小文字のbarewrodを使うのは習慣として勧められません。大文字を使うか、例に挙げたようにmy変数を使いましょう。 ただし古いバージョンのPerlだと使えませんが。 それと、読み込んだデータを2度splitしていますが、一度目のsplitの 結果である $sentenceと$filenameを使っていないようですがなぜでしょう? #!/usr/local/bin/perl use strict; use warnings; print "Content-type: text/html\n\n"; &hoge; sub hoge{ my @all = <DATA>; my @hoge; my $score; for (@all){ my $sentence; my $filename; ($sentence, $filename) = split /,/, $_; $score++; #push @hoge, ($score, $_, "<br>\n"); push @hoge, [$score, $_, "<br>\n"]; } #print join ':::', @hoge; #print "#####\n"; #use Data::Dumper; #my @mapped = map {[$_, split /,/, $_->[1]] } @hoge; #print Dumper(@mapped); # @hoge = map {$_->[0]} sort {$b->[1] <=> $a->[1]} map {[$_, split /,/]}@hoge; my @sorted = map { $_->[0] } sort { $b->[2] <=> $a->[2]} map {[$_, split /,/, $_->[1]] } @hoge; #print Dumper(@sorted); foreach my $item (@sorted) { print join(':', @{$item}), "\n"; } } __END__ ,123,abc.txt ,456,def.txt ,789,ghi.txt ,123,jkl.txt ,456,mno.txt ,789,pqr.txt
その他の回答 (3)
- sakusaker7
- ベストアンサー率62% (800/1280)
補足です。 pushした順に番号をつけて出力すればいいのなら、 pushではなくunshiftで配列に追加するか、 foreachでとりだすときにreverseしてやれば良くて、 わざわざ重いソートなんてやる必要ないのでは。
補足
おっしゃる通りなのですがこのあと色々コードを追加して処理するので 質問に シュワルツ変換を用いて と付け加えさせていただきました。
- ren10
- ベストアンサー率52% (9/17)
興味があったもので… 私も #2 の方が回答されてるように @hoge の中身が怪しいかと… push @hoge, ($score,$_,"<br>\n"); これでは $hoge[0] = "1"; $hoge[1] = ",123,abc.txt\n"; $hoge[2] = "<br>\n"; $hoge[3] = "2"; $hoge[4] = ",456,def.txt\n"; $hoge[5] = "<br>\n"; という風に値が入ってしまいますが… 下記のような形を望んでいるのでは? $hoge[0] = "1,123,abc.txt\n,<br>\n"; $hoge[1] = "2,456,def.txt\n,<br>\n"; こうした上で配列 @hoge の第一項($score)でソートすれば @hoge = map {$_->[0]} sort {$a->[1] <=> $b->[1]} map {[$_, split /,/]}@hoge; これで期待通りの結果が得られるのでは…
お礼
てっきり push @hoge, ($score,$_,"<br>\n"); とすれば $hoge[0] = "1,123,abc.txt\n,<br>\n"; $hoge[1] = "2,456,def.txt\n,<br>\n"; となるものだと思っていました。 これじゃあ上手くできませんよね。 ご回答ありがとうございました。
- BLUEPIXY
- ベストアンサー率50% (3003/5914)
>push @hoge, ($score,$_,"<br>\n"); が悪いと思います。 >push @hoge, "$score$_<br>\n"; とでもすればいいんじゃないかと思います。 あと、 for (@all){ の後に、 chomp; を入れた方がいいかも・
お礼
カッコだけでこんなに処理が変わってしまうとは思っていませんでした。 基本から復習したいと思います。 ご回答ありがとうございました。
お礼
データ構造までは把握していませんでした。 習慣やDumper等も含めて、もう一度丁寧にPerlを学ぼうと思います。 splitはこのcgiに今後コードを追加しようと思っているのですが、消し忘れてしまったものです。 ご回答ありがとうございました。