重要なお知らせ

「教えて! goo」は2025年9月17日(水)をもちまして、サービスを終了いたします。詳細はこちら>

電子書籍の厳選無料作品が豊富!

シュワルツ変換の不具合で困っています。

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

と出力させたいのです。
どこをどのように変えればよいでしょうか。
宜しくお願いします。

A 回答 (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
    • good
    • 0
この回答へのお礼

データ構造までは把握していませんでした。
習慣やDumper等も含めて、もう一度丁寧にPerlを学ぼうと思います。
splitはこのcgiに今後コードを追加しようと思っているのですが、消し忘れてしまったものです。
ご回答ありがとうございました。

お礼日時:2006/06/11 12:59

補足です。


pushした順に番号をつけて出力すればいいのなら、
pushではなくunshiftで配列に追加するか、
foreachでとりだすときにreverseしてやれば良くて、
わざわざ重いソートなんてやる必要ないのでは。

この回答への補足

おっしゃる通りなのですがこのあと色々コードを追加して処理するので
質問に シュワルツ変換を用いて
と付け加えさせていただきました。

補足日時:2006/06/11 12:44
    • good
    • 0

興味があったもので…


私も #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;

これで期待通りの結果が得られるのでは…
    • good
    • 0
この回答へのお礼

てっきり
push @hoge, ($score,$_,"<br>\n");
とすれば
$hoge[0] = "1,123,abc.txt\n,<br>\n";
$hoge[1] = "2,456,def.txt\n,<br>\n";
となるものだと思っていました。
これじゃあ上手くできませんよね。
ご回答ありがとうございました。

お礼日時:2006/06/11 13:04

>push @hoge, ($score,$_,"<br>\n");


が悪いと思います。
>push @hoge, "$score$_<br>\n";
とでもすればいいんじゃないかと思います。
あと、
for (@all){
の後に、
chomp;
を入れた方がいいかも・
    • good
    • 0
この回答へのお礼

カッコだけでこんなに処理が変わってしまうとは思っていませんでした。
基本から復習したいと思います。
ご回答ありがとうございました。

お礼日時:2006/06/11 13:01

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!