• ベストアンサー

Perlのソートについて

ハッシュを利用して今ソートできるプログラムを作成したのですが、 重複するデータは除外されてしまうようで、どうしたら除外されずに ソートできるかを教えていただきたいです。 <例> 文字 よみ  No      橋  はし  1      橋  はし  3      箸  はし  2 というデータがあったとして、今のプログラムを実行すると・・・ <結果> 箸  はし  2 キーがよみなので3番目のデータだけ残ります。キーを漢字に したとしても1番目のデータは残らないのですが、どうしてらよいのでしょうか。 <理想的な結果>      橋  はし  1      箸  はし  2      橋  はし  3 一番いいのが上のような結果で、Excelのソートのような感じで、第1キーはよみで第2キーはNoとかのソートはPerlでできないでしょうかね?? どなたか分かる方がいたら教えていただきたいです。 よろしくお願いします。

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

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

  • ベストアンサー
回答No.5

$form_file = "sort2.log"; $to_file = "sort2.txt"; open(F1, $form_file) || die "$form_file をオープンできません:$!\n"; open(F2, ">$to_file") || die "$to_file を作成できません:$!\n"; foreach(sort useSort <F1>){ print F2 $_; } close(F2); close(F1); sub useSort{ (split(/\t/,$a))[1] cmp (split(/\t/,$b))[1] || (split(/\t/,$a))[2] <=> (split(/\t/,$b))[2] } 多分こんな感じになるんじゃないですかね。 <F1>の中身が下のようになっていたらのお話です。 橋\tはし\t2 橋\tはし\t1 橋\tはし\t3

Chiaki---
質問者

補足

返事遅くなって申し訳ありません。 プログラムやってみました。上手くソートができていました。 しかし、プログラムがいまいち分からないので、今後の勉強の為にも もうちょっと詳しく教えていただきたいです。 foreach(sort useSort <F1>){ print F2 $_; } close(F2); close(F1); sub useSort{ (split(/\t/,$a))[1] cmp (split(/\t/,$b))[1] || (split(/\t/,$a))[2] <=> (split(/\t/,$b))[2] } の意味を教えていただきたいです。よろしくお願いします。

その他の回答 (4)

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.4

#3>Noについての Noは、どのように決定するのでしょうか? 置換前のファイルに手入力で追加するのですか? 現在のような $mozi{$yomi} = "$mein"; では、同じ読みが1つしか保存されません $mozi{'はし'}=['橋','箸','端']; みたいな構造、(位置がNoをあらわす)とするか $mozi{'はし'}=[['橋',1],['箸',2],['端',3]]; のような構造がいいかもしれません。 ところで、例のように 橋 はし 1 橋 はし 3 みたいに同じ文字、同じ読みで違うNoが付くことはあるんですか

Chiaki---
質問者

補足

文字の保存の仕方がいけないのですね・・・。少し考えてみます。 ありがとうございます。 同じ文字でNoが違うバージョンはたくさんあるんですよね。 それがなかったら、簡単にできるんですが。

  • BLUEPIXY
  • ベストアンサー率50% (3003/5914)
回答No.3

ハッシュでどんな風にデータが格納されているんでしょうか? 「ソートできるプログラムを作成した」を補足で挙げられますか?

Chiaki---
質問者

補足

print"置換元のファイル名を指定ください:"; $form_file = <STDIN>; print"置換後のファイル名を指定してください:"; $to_file = <STDIN>; chomp($form_file, $to_file); open(F1, $form_file) || die "$form_file をオープンできません:$!\n"; open(F2, ">$to_file") || die "$to_file を作成できません:$!\n"; while ($line = <F1>) { chomp $line; ($mein, $yomi) = split (/\t/, $line); $mozi{$yomi} = "$mein"; } foreach $value (sort keys %mozi) { print F2 "$mozi{$value}\t$value\n"; } 作成してみたのが、これです。 まだNoについてのプログラムはわからないので作成できていませんが・・ できますかね??よろしくお願いします

回答No.2

#!/usr/local/bin/perl use strict; my @DATA = ( [ '橋', 'はし', 1 ], [ '橋', 'はし', 3 ], [ '箸', 'はし', 2 ], ); @DATA = sort { $a->[2] <=> $b->[2] } sort { $a->[1] cmp $b->[1] } @DATA; for (@DATA) { print $_->[0] . $_->[1] . $_->[2] . "\n"; } exit; 検証していませんので自信はないです:)

  • galluda
  • ベストアンサー率35% (440/1242)
回答No.1

がると申します。 んっと……記述されているデータだけを考えると単純に「Noをキーにしてソート」で片付くと思うのですが。 もし「それじゃNG」なようであれば、もう少し細かく「ソート条件」を教えていただければ、多分返答できるかと思います。

関連するQ&A

  • ハッシュで重複キーを認める方法について

    現在、Perlを用いてBootstrap法という方法論によるデータの加工を行っています。 その中でハッシュを使います。 それはkeyでsortしvalueを並び替え、その並び替えたvalueを処理することが目的です。  例えばこのようなものです。  Height  Weight   170.6  54.8   185.7  87.2   156.1  78.6   185.7  87.2   164.5  54.7   156.1  45.3    :     : 以上のようなデータに対し、Heightをkeyにsortし、Weightを並び替え、その並び替えたWeightの値を上から順に同数ずつ、複数のグループに分類することが目的です。 ですがハッシュでは重複keyはvalueが上書きされてしまうので、元のデータより少なくなってしまい正確なsort、並び替えができません。 Perlでこの重複を回避する方法を教えていただきたく思います。

    • ベストアンサー
    • Perl
  • csvファイルのソート

    perlで、csvファイルをある項目でソートした結果を表示したいのですが(つまりエクセルで並び替えをするようなこと)、ハッシュ配列等を使用しないとできないのでしょうか? 項目(列)は10項目くらいあります。

    • ベストアンサー
    • Perl
  • 【javascript】ハッシュのキーをソートして取り出したい

    ハッシュのキーをソートして取り出したいです。 perlで表現すると、以下の様なかんじです。 foreach $key (sort keys %hash) { ... } そこで、prototype.jsを使って以下の様に書いてみました。 <html> <head> <script type="text/javascript" src="prototype.js"></script> </head> <body > <script > var table = {c:'C', b:'B', a:'A'}; $H(table).keys().sort().each(function(key){ alert(key + ' ' + table[key]); }); </script> </body> </html> 他に良い方法ありましたら、教えてください。

  • perlでCSVをソートする方法について

    perl初心者です。いつもありがとうございます。 perlでcsvファイル(1行のカラム数は200)、総行数は約3万行のファイルを37番目のカラム(-25以上25未満の数値データ)で降順ソートしその値によって行数がだいたい均等になるよう3分割し、2番目のカラムに文字でも数字でもよいのですがその4つのグループごとにフラグ(例えば1,2,3)を入れたいと思ってます。グループ化については境目の37番カラムの値は重複している場合が多いと思うのですがその場合は下(別に上でもかまいません)に入れるものとします。 ソートロジックは過去の質問を参照して理解しましたがグループ化しフラグを入れるルーチンがうまく作れません。下記のように作ったのですがこの先同じことを何度もやらなくてはならないので先に進めません。どなたかお助けください。最終的にやりたいことはカラム37でグループ化→カラム2にフラグを立てる、次にカラム2とカラム38(-25から0までの数値)でソートし同様に同じ行数になるようにグループ化→カラム3にフラグを立てる、さらにカラム2とカラム3とカラム39(-25以上25未満の数値データ)でソートし・・・同様に繰り返し最終的に1グループが100件(行)~150件(行)になるようにしたいのです。つまり約3万件のデータを3*4*2*4*2=192分割(5列の値で分類)したい、そしてどのような範囲で分割したかという情報も得たいのです。 use strict; use warnings; use utf8; use Encode; binmode STDOUT, ':encoding(utf-8)'; my $dir = './data'; # 処理するディレクトリ my $motoFile = 'customer.txt'; # もとファイル open my $fh, '<:encoding(cp932)', "$dir/$motoFile" or die 'ファイルが開けません。',"$!"; my %sorted; while (my $line = <$fh>) { my $key = (split /,/, $line)[37]; push @{$sorted{$key}}, $line; if (@{$sorted{$key}} == 1000) { open OUT, '>>:encoding(cp932)', "$dir/$key.tmp" or die "Can't open: $!"; print OUT @{$sorted{$key}}; close OUT; @{$sorted{$key}} = (); } } open OUT, '>:encoding(cp932)', "$dir/out.txt" or die "Can't open: $!"; foreach my $key (sort { $b <=> $a } keys %sorted) { if (-e "$key.tmp") { open IN, '<:encoding(cp932)', "$dir/$key.tmp" or die "Can't open: $!"; print OUT while <IN>; close IN; } print OUT @{$sorted{$key}} if @{$sorted{$key}}; } close OUT; #↓↓↓↓ここからフラグを作成するルーチン # 行数を調べ3つに分けるルーチン my @colum37; open IN, '<:encoding(cp932)', "$dir/out.txt" or die 'ファイルが開けません。',"$!"; my @in = <IN>; close IN; my $gyousuu = scalar(@in); my $amari = $gyousuu % 3; if ($amari == 0) { my $groupGyousuu = ($gyousuu-$amari)/3; print "総行数は$gyousuu","で、1グループの行数は$groupGyousuu","ほど、余りは$amari\n"; # あまりが0の時、group1は@inの0行 ~$groupGyousuu-1行まで #         group2は@inの$groupGyousuu行 ~$groupGyousuu*2-1行まで #         group3は@inの$groupGyousuu*2行~$groupGyousuu*3-1行まで foreach my $num (1..2) { push @colum37, (split /,/, $in[$groupGyousuu*$num])[37]; # これは境目の先頭の37番目 } print "@colum37\n"; #これでここまでは完成、分けるべき値がこの配列に入っている。 open OUT, '>:encoding(cp932)', "$dir/out.txt" or die "Can't open: $!"; foreach my $line (@in) { my @line = split /,/,$line; if ($line[37]>=$colum37[0]) { $line[1] = 1; }elsif ($line[37]>=$colum37[1] and $line[37]<$colum37[0]) { $line[1] = 2; }elsif ($line[37]<$colum37[1]) { $line[1] = 3; } $line = join (',',@line); print OUT $line; } close OUT; } elsif ($amari == 1) { この後未作成

    • ベストアンサー
    • Perl
  • ソート順の配列に順位表示する

    Perlで、大きいソート順になっている配列があります。 その中には重複しているデータもあります @list = (100,80,80, 50, 50, 45, 10, 0, 0, 0); のような配列を @ranking = (1,2,2, 4, 4, 6, 7,10,10,10); と順位を格納させたいです。 簡単な方法がありましたら、教えてください。

    • ベストアンサー
    • Perl
  • エクセル:  ソート後処理でデータ選出

    エクセルSheet1の表、項目1に県名、項目2に市名が載っている表があります。(ランダムにデータ間の重複あり)、表中に実際にある項目1、と項目2の組合せで、県名を第1キーであいうえお順に ソートし、市名を第2キーで同様ソートしたものを重複無くした表をsheet2に作りたいのですが、 重複無くした表をsheet2にするという操作はどうすればいいのでしょうか。よろしくお願いします。

  • Perl(cgi)ファイルからMySqlで管理しているデータベース制御に関して質問

    Perl(cgi)ファイルからテーブル内の一定の項目をDELETEしようとしています ランダムに選択させる値をハッシュに格納し読み込み、削除を試みています。 foreach $key (keys %hash) { # 取り出した値を$noに代入 $no = $hash{$key}; # SQL発行 $sql = $db->prepare("DELETE FROM テーブル名 WHERE レコード指定名='$no'"); # SQL実行 $sql->execute; } 上記の方法で問題なく実行できているのですが、ご覧のようにハッシュに格納されている数だけSPQを実行しているため効率が悪い、と 担当者から指摘をうけました。 PHPであればSPQの実行あと、for文で『 レコード指定名='_no'』の部分だけをループさせることができたのですが Perlではうまくいきません。ご教授ください。よろしくお願いします。 ちなみにPerlをはじめとしてプログラムそのものを勉強し始めて1ヶ月の初心者です。

    • ベストアンサー
    • MySQL
  • Javaのソートに関する質問です。

    Javaのソートに関する質問です。 CSVから取得したデータの一つをキーとして降順にソートしたいのでしょうが、どのような方法が効果的でしょうか?関数が利用できるのであれば関数を使用したいのですが。。。 データの詳細を以下に記載します。 環境 JavaSE5.0 CSVデータ ※ソート条件 ・キー内容は「wwwwwwww-xxxxxxxx-yyyyyyyy-zzzzzzzz」という形式で、 「wwwwwwww」が1番、「xxxxxxxx」が2番、というように、左側の数値が優先されます。 (ソート前)キー内容 タイトル 11111111-22222222-33333333-4444444 テスト1 22222222-33333333-44444444-5555555 テスト2 11111111-00000000-22222222-3333333 テスト3 22222222-44444444-55555555-6666666 テスト4 (ソート後)キー内容 タイトル 11111111-00000000-22222222-3333333 テスト3 11111111-22222222-33333333-4444444 テスト1 22222222-33333333-44444444-5555555 テスト2 22222222-44444444-55555555-6666666 テスト4

  • PerlでのCSV書き込みについて質問です。

    perl初心者です。 perlで投票のプログラミングを作ってるのですが、 どうもうまく動きません。 やりたいことは ・投票されたら  1)csvを読み込む  2)該当するNOのカウントをアップ  3)csvに書き込む という単純なことなのですが、 投票してもカウンタは0のままになってしまいます。 書き込み部分のプログラムが間違っているとは思うのですが 何が間違っているのかがどうしてもわかりません。 どなたかお知恵を貸してくださいm(__)m プログラムは下記のようになっています。 ================= foreach my $key (@key) { $val = $in{$key}; $in{$key} = &Jcode::convert(\$val, 'sjis'); } # データオープン open(DAT,"+< $datfile"); flock(DAT, 2); my @data; while (<DAT>) { push(@data,$_); if (eof) { last; } } # データ書き込み truncate(DAT, 0); seek(DAT, 0, 0); my $i=1 while (i<11){ my ($no,$name,$count) = split(/,/, $data[$i]); if($val eq $no){$count++;} if (eof) { last; } $i++; print DAT "$no,$name,$count,\n"; } close(DAT); ================= どうぞよろしくお願いします。

    • ベストアンサー
    • Perl
  • クイックソートを実現するプログラム(java)

    クイックソートを実現するプログラムを組みたいのですが、やり方がよくわかりませんでした。 ただし、データは全て整数で重複は無い場合です。 できれば、フローチャートも含めて回答よろしくお願いします。

専門家に質問してみよう