• ベストアンサー

ファイルソート方法

以下のようなテキストを入力してソートしたいのですが、どのようにプログラムを書けばよいのでしょうか? <<入力>> Fruit Apple Vegetable Tomato Friut Orange Fruit Grape Fish Salmon Vegetable Carrot <<ソート>> Fruit : Apple Orange Grape Vegetable: Tomato Carrot Fish : Salmon ソートしたあと、グループ毎の処理をしたいと思っています。 入力は数千行で、グループ(Fruit, Vegetable...)の個数などは不明です。

  • Perl
  • 回答数3
  • ありがとう数4

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

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

ソートするのは2番目の単語だけですか? FruitとかVegetableもソートするなら Fish : Salmon Fruit : Apple Orange Grape Vegetable: Tomato Carrot になると思うのですが。 とりあえずソートするようにしたのが↓です open my $FH, "file.txt" or die $!; my %food; # それぞれの行の食べ物を$food{$name}に配列のリファレンスとして保存 while (<$FH>) { chomp $_; my ($name, $group) = split / /, $_; # 空白で区切る push @{$food{$name}}, $group; # 配列のリファレンスに保存 } foreach my $name (sort keys %food) { print "${name}:" . (join ' ', @{$food{$name}}) . "\n"; }

tk_1980024
質問者

お礼

有難うございます。「配列のリファレンス」「無名配列」を調べて完全に理解できました。 なお、 > FruitとかVegetableもソートするなら のソートはあまり気にしておりませんでした。 以下自分への備忘録もかねて理解したことをかきました。もし誤りがありましたらご指摘いただければと思います。 ■データ構造のイメージ %food = ("Fruit" => [Orange, Grape, Apple], "Vegetable" => [Tomato, Carrot], "Fish" => [Salmon] ); # [a, b, c]は無名配列の初期化方法 ■無名配列まとめ $ref_array # 配列のリファレンス #「配列」は@$, 「hash」は%$でアクセス push (@$ref_array, "Watermelon"); #配列へ値を追加 @$ref_array->[$i] #配列の値へアクセス > push @{$food{$name}}, $group; # 配列のリファレンスに保存 > print "${name}:" . (join ' ', @{$food{$name}}) . "\n"; ■FYI: 名前つき配列のリファレンス @array =(); $ref_array = \@array; #配列へのリファレンス http://takenaka-akio.cool.ne.jp/doc/perl_kiso/reference3.html

その他の回答 (2)

回答No.3

> @$ref_array->[$i] #配列の値へアクセス 非常に惜しいのですがこれだけ違います。 配列の値へアクセスするには $ref_array->[$i] か ${$ref_array}[$i] です。 後者は見た目の通り見にくいため、一般的に前者の書き方が好まれます。

tk_1980024
質問者

お礼

有難うございます。 後者の書き方も記憶に止めておきます。

  • ORUKA1951
  • ベストアンサー率45% (5062/11036)
回答No.2

エラー対策 ・品名が二文字からなるもの。 ・前後に、余分な空白がある場合。 ・品名中に連続した空白文字がある場合。 ・すでに上がっている品名 とりあえず、ここまで。 ☆ 大文字小文字の処理はしていない。  すべて小文字にtr///でも使って変換してチェックし、出力時に先頭文字を大文字にするのがよいかと #!/usr/local/bin/perl use strict; my (%Check,%List,$key); open(IN,"<input.text") or die; while(<IN>){ chomp; if( m#(\w+) (.+)$# ){ my $kind = $1; my $name = $2; $name =~ s/^\s+//g;# 名前の前の空白文字削除 $name =~ s/\s+$//g;# 名前の後の空白文字削除 $name =~ s/(\ +)/ /g; # 単語中の連続した半角スペースを1文字に if( $Check{$name}>0){ next;} # すでに登録されていればスキップ $Check{$name} = 1; push @{$List{$kind}} ,"$name";# ハッシュの配列に格納 } } close IN; open OUT,">output.txt"; foreach $key (sort keys %List){ # グループ名でソート my @outList = sort @{$List{$key}}; # リスト内をソート # リスト値を,で連結するなら--- my $line = join ",",@outList; print OUT "$key: $line\n"; # ,で連結しないなら早い処理(上の2行をコメントアウトして、こちらの#をとる。 # ※二単語からなるものは、上の処理が良い。 # print OUT "$key: @outList\n"; } close OUT; __END__ inout.text Fruit Apple Vegetable Tomato Fruit unflower seed Fruit anana Vegetable cucumbers Vegetable broccoli Vegetable pumpkins Fish Snapper Vegetable Tomato Fish Tuna Vegetable broccoli Vegetable cauliflower Fruit unflower seed Fruit Orange Vegetable asparagus Vegetable broccoli Fish Patagonian toothfish Fish Cod Fruit unflower seed Fruit edge apple Vegetable asparagus Fruit Grape Fish Salmon Vegetable Carrot Fruit Lemon Fruit Lime Fruit Grapefruit Vegetable Tomato Friut Orange Fruit Grape Fish Salmon Vegetable Carrot Fruit ranberry output.txt(出力例) Fish: Cod,Patagonian toothfish,Salmon,Snapper,Tuna Fruit: Apple,Grape,Grapefruit,Lemon,Lime,Orange,anana,edge apple,ranberry,unflower seed Vegetable: Carrot,Tomato,asparagus,broccoli,cauliflower,cucumbers,pumpkins

tk_1980024
質問者

お礼

コード拝見致しました。確かに、 if( $Check{$name}>0){ next;} # すでに登録されていればスキップ $Check{$name} = 1; のチェックは実際には必要で実装していたところです(この方法はスマートで気に入りました)。 どうも有難うございます。

関連するQ&A

  • 定石? perlで入力ファイルを処理する方法

    以下のようなファイルを入力して、配列/連想配列に格納、これを後段の処理に利用したいと考えています。結構複雑なことをやってようやく処理できたのですが、もっと良い方法はありませんでしょうか。 逆に入力ファイルのフォーマットを処理しやすいものにしてしまっても構いません(perl形式で記述してrequireする方法はここではNGとします)。アイディア宜しくお願い致します。 1. #はコメント 2. 最終イメージ  Vegetable: Tomato, Lettuce, Potato Fish : Salmon, Tuna, Fruit : Banana, Orange ※ ####~次の####までを塊として処理する部分で、ちょっと冗長な気がしています --- >8 --- >8 --- >8 --- >8 --- >8 # This is comment line # File created by ... # since 5/May/2009 #### Vegetable Tomato Lettuce Potato # Carrot <-- Comment line #### Fish Salmon Tuna #### Fruit Banana Orange --- >8 --- >8 --- >8 --- >8 --- >8 <<スクリプト例>> # ここでは@keyにカテゴリ(Vegetable, Fish, Fruit)、@valueに各々の食品名(Tomato, lettuce,...)を入れています #! /usr/bin/perl my $flag_first_match = 1; my $flag_hit = 0; my @key; my @value; open (LIST, "aaa.txt") || die "open error"; while(<LIST>){ if($flag_hit == 1){ $flag_hit = 0; $flag_seek = 1; if($flag_first_match==1){ $flag_first_match = 0; } } if(m/####\s+(.*)$/){ $key_tmp = $1; $flag_hit = 1; $flag_seek = 0; } chomp(); if(m/^\s*$/){next;} if(m/^#\s+/){next; } if($flag_hit==1 && $flag_first_match ==0 ){ # for on-going loop push(@value, $ref_tmp); } if($flag_hit == 1){ # for next loop push(@key, $key_tmp); $ref_tmp = []; } if($flag_seek == 1){ push(@$ref_tmp, $_); } } close(LIST); ### 印字確認 { local $, = ", "; for($i=0; $i < @key; $i++){ printf ("%2d | %-35s: ", $i, $key[$i]); foreach $ref ($value[$i]) { for ($j=0; $j < @$ref; $j++){ print "$j= @$ref[$j] "; } } print "\n"; } } <<出力>> 0 | Vegetable : 0= Tomato 1= Lettuce 2= Potato 1 | Fish : 0= Salmon 1= Tuna 2 | Fruit :

    • ベストアンサー
    • Perl
  • 2つの配列のソート

    配列のソートについての質問です。 よろしくお願いします。 var syouhin = new Array(10); //商品名 var kosuu = new Array(10);  //商品個数 syouhin[0] = "apple"; syouhin[1] = "orange"; ... syouhin[9] = "banana"; kosuu[0] = "4"; kosuu[1] = "2"; ... kosuu[9] = "5"; 個数は[]の数字の商品に対応。 個数をソート kosuu.sort(); ここでソートした個数に対応して商品もソートして、 for (i=0; i<kosuu.length; i++){ document.write(syouhin[i],kosuu[i],", "); document.write("<br>"); } と表示したいのですが、ソートした個数に対応した商品のソートの 仕方がわかりません。 どのような方法があるのでしょうか? よろしくお願いします。

  • C言語について質問です。教えてください。

    C言語について質問です、教えてください。 以下のようなテキストファイルがあるとします。 apple,111 orange,222 grape,333 lemon,444 banana,555 一行ずつorange というものがあるかないかを探して、 なければ次の行を検索、 あれば、その該当行のカンマで区切った二つ目のデータ(ここでいう222)を とってきて、break処理 どのようにくめばいいでしょうか>< 誰か教えてください。 よろしくお願いいたします。

  • 多次元配列を[キー:値]の形でランダム表示に

    <?php $fruit = array( 'apple' => array('ふじ','ジョナゴールド'), 'orange' => array('みかん','バレンシア'), 'grape' => array('巨峰','マスカット') ); foreach ($fruit as $key => $value) { foreach ($value as $key2 => $value2) { echo '<p>' . $key . ' : ' . $value2 . '</p>' . "\n"; } } ?> 上記コードにて多次元配列をループさせて以下の様に表示させています。 apple : ふじ apple : ジョナゴールド orange : みかん orange : バレンシア grape : 巨峰 grape : マスカット これを下の様にシャッフルした形でランダムに表示させたいと思い、自分なりに試行錯誤してみたのですが、思うような結果を出す事が出来ずに悩んでいます。 何か良い方法がありましたらアドバイスを頂ければと思います。 よろしくお願い致します。 grape : 巨峰 apple : ふじ orange : みかん grape : マスカット orange : バレンシア apple : ジョナゴールド

    • ベストアンサー
    • PHP
  • 連想配列に追加ってできるン?

    $fruit = array("Apple" => "りんご", "Orange" => "みかん", "Grape" => "ぶどう"); これに"EVA" => "エヴァンゲリオンの略"を追加したいんだけど、色々やったけどわからン。 どうしたらできるン?

    • ベストアンサー
    • PHP
  • 二次元配列の基礎の基礎

    二次元配列という概念を知って興味を持ち、 ちょっと自分でやってみたのですが、どうしてもうまくいきません。(T-T) php.netやgoogleであちこち2時間以上見てまわりましたが、 あまりに初歩的過ぎるのか、難しいものばかりで撃沈しました...。 お手数ですが、どうぞよろしくお願いいたします。 <?php $fruits[] = array("orange", "みかん"); $fruits[] = array("apple", "りんご"); $fruits[] = array("grape", "ぶどう"); print_r($fruits); // 出力結果 // Array ( [0] => Array ( [0] => orange [1] => みかん ) [1] => Array ( [0] => apple [1] => りんご ) [2] => Array ( [0] => grape [1] => ぶどう ) ) // 以下でぶどうと出したいのですが、Array[1]と表示されてしまいます。 echo "$fruits[2][1]"; ?>

    • 締切済み
    • PHP
  • Word:英文字と日本語間の文字調整

    Word2003 SP1を使用しています。 テキストBOX内で英文と日本語文の複合文を入力すると、折り返し部分で変になります。 どうも英単語の途中で折り返す事を許さない設定になっているようです。 これを解除する方法は無いんでしょうか? あれば教えて頂けると幸いです。 例えば 「tomatoとappleは果物です。」を入力すると ↓ tomato_____と appleは果物 です。 となります(____の部分は空白です) appleという単語が2行になるのを許さないようなのです。 これを tomatoとappl eは果物です。 としたいのですが・・・

  • リストを分解してのSQLデータ抽出方法

    ド初心者です。カテ違いだったらごめんなさい。 あるデータを抽出したいのですが全く検討つかずで困っています。 SQLの組み立て方(?)をご教授頂けないでしょうか? fruits    order ----------    -------------------------- apple    orange, apple orange    orange, apple, grapefruit grapefruit   grapefruit grapefruit   orange, grapefruit, apple orange   apple, orange ▼▼ 上記のテーブルを使用して以下のような抽出結果を出したいです ▼▼ fruits  rank1  rank2  rank3 ----------  -----  -----   ----- apple   1   2    1 orange   3   1    0 grapefruit  2   1    1 appleがorderカラムで1番目に入っている行は何行あるかをrank1に appleがorderカラムで2番目に入っている行は何行あるかをrank2に appleがorderカラムで3番めに入っている行は何行あるかをrank3に orangeがorderカラムで1番目に入っている行は何行あるかをrank1に orangeがorderカラムで2番目に入っている行は何行あるかをrank2に つづく ・ ・ というように出したいです。何か良い方法はないでしょうか。 ちなみにBig QueryのstandardSQLを使用しています。 よろしくお願い致します。

  • VB.NET parallel arrayからの取り出し方

    VB.NET 初心者ですのでお手やわらかにお願いいたします。 今週の売利上げを各商品ごとにTextboxへInputします。それをSortして一番売り上げ数の高い数字とその商品名をLabelHighNumberとLabeItemlNameに出します。分かりやすいように3商品と簡単な数字を使いますのでご了承ください。input数字はすでにToInt32でConvertしてあるもとします。どうもこれでは、Sort後、売り上げ個数の高い18だけ引っ張ってきてOrangeがでてきません。Arrayの中で二つがつながってないんでしょうか。 商品名はすでにLabelでscreenにでていますので、売り上げ個数だけのInputになります。 このようなイメージです。 Apple 10 Banana 5 Orange 18 Dim strItemName() as string {"Apple", "Banana","orange"} Dim intInputProductNumber() as integer {10, 5, 18}  Dim intIndexLocaion as integer ’一番高いIndexをとるためSortしました Array.Sort(inInputProductNumber) 'ここでIndexが一番大きい2をとりました。(0,1,2の中で) intIndexLocation = inputProductNumber (2) 'ここでは18と出てきます。 me.LabelHighNumber.text = indIndexLocation.toString ’しかし、Orangeとはでてきません。 me.LabelItemName.text = strProductName(intIndexLocation) よろしくご教示お願いいたします。

  • 異なるファイルからの情報を齟齬がないかを調べる。

    こんばんは。VB初心者です。お聞きしたいのですが、2つの異なるファイルからの情報に齟齬がないかをマクロで調べたいのですが(できればIF関数やEXACTを使わないで)、どうもうまくいきません。 例えば、下のような情報がSHEET1にある場合、 File1 Apple    Orange Banana Plum    Mango Cucumber Carrot Tomato Lettus Mellon File2 Orange Apple  Banana Plum Mango Cucumber Carrot Tomato Mellon Lettus マクロを使って、下のように結果を求めたいのですが、どのワークシートファンクションを使えばいいのかわかりません。マッチングやテストもあるのですが、どうもよくわかりません。 FALSE FALSE TRUE  TRUE TRUE TRUE    TRUE TRUE FALSE FALSE 自分で少し考えてみたのですが、アドバイスをよろしくお願いします。 Sub Test() Dim lngLine As Long Dim lngTest As Long   Worksheets("Sheet1").Select GYO1 = Sheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row + 1 GYO2 = Sheets("Sheet1").Cells(Rows.Count, 1).End(xlUp).Row + 2 lngTest = 0 If Len(Range("A2")) > 0 Then lngLine = Range("A1").End(xlDown).Row lngTest = WorksheetFunction.???????? End If Range(Cells(GYO1, 1), Cells(GYO1, 1000)).Value = lngTest Range(Cells(GYO2, 1), Cells(GYO2, 1000)).Value = lngTest End Sub

専門家に質問してみよう