質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

  • Linux

    4053questions

    Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

  • CSV

    712questions

    CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

  • Perl

    465questions

    Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

Perlでcsvファイルのデータ処理について教えてください

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 313

soso

score 4

 前提・実現したいこと

perlでlinuxサーバー内のcsvのログ解析をしており、起点($original)と
目的地($destination)の組合せ別の集計値を集計値の降順で表示したいです。

ここに質問の内容を詳しく書いてください。
perlでcsvファイルを集計するプログラムを作成していますが、行き詰っておりお知恵を頂きたく投稿しました。
csvファイル内の起点($original)と目的地($destination)という項目があり、その二つの組合せの合計数をそれぞれ集計し、集計値が降順に並ぶようなプログラムを作成したいと考えています。

現状では下記のように起点($original)ごとの組合せでの集計値が降順に並んでいますが、
|original|destination|集計値|
|100|101|10|
|100|102|5|
|100|103|1|
|90|101|15|
|90|102|4|
|80|101|8|
|80|102|7|

下記のように全ての集計値が降順で並ぶようにプログラムをかきたいと思っております。

|original|destination|集計値|
|90|101|15|
|100|101|10|
|80|101|8|
|80|102|7|
|100|102|5|
|90|102|4|
|100|103|1|

何卒お力添えのほどお願いいたします。

■■な機能を実装中に以下のエラーメッセージが発生しました。

 発生している問題・エラーメッセージ

 該当のソースコード

ここに言語名を入力
Perl
use strict;
use warnings;

open(FILE, 'example.csv') or die "$!";

my $info = {};
while (my $line = <FILE>) {
my($DateTime, $original, $destination, $stopover1, $stopover2, $stopover3, $Model, $tiles, $Method, $Time,
$TimeDifference, $Flag, $Date, $searchTime, $searchDay, $rideDate, $rideTime, $rideDay)
= split(/,/, $line);

++$info->{$original}->{$destination};

}
close(FILE);

foreach my $original( sort keys %$info){

foreach my $destination(sort {${$info->{$original}}{$b} <=> ${$info->{$original}}{$a}} keys %{$info->{$original}}){
my $count = $info->{$original}{$destination};
my @rec = ($original, $destination, $count);
print join(',', @rec). "\n";
}
}

 試したこと

ここに問題に対して試したことを記載してください。

 補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

perlのsort関数では独自の「比較関数」が利用できます。

@a = (1,3,2,4,10,5,20);

# デフォルトの比較関数は{$a cmp $b}
@a1 = sort @a;
# 数値として比較して昇順にソート
@a2 = sort {$a<=>$b} @a;
# 数値として比較して降順にソート
@a3 = sort {$b<=>$a} @a;

比較関数の書き方は独特なのでマニュアルを確認してください。要点は、

  1. 比較すべき要素二つをそれぞれ$a, $bで表す。
  2. $a>$bなら1, $a<$bなら-1, $a==$bなら0を返すように式を立てる。

次に対象データですが、2段のハッシュになっているため、少しややこしいです。ソートをかけるにはまずこの階層を解きたいところです。map関数が使えるでしょう。

これらを組み合わせ、無名リスト化→ソート→出力という順番を考えてみました。試してませんが、最後のforeachループを次のような雰囲気で書き換えればいいでしょう。

map {printf "%s %s %s\n", $_->[0], $_->[1], $_->[2]}
  sort {$b->[2] <=> $a->[2]}
    map {$k1=$_; map {$k2=$_; [$k1, $k2, $x->{$k1}{$k2}] } keys $x->{$k1}} keys %$info

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/20 11:57

    できるだけオリジナルのソースを活かす方法として考えてみたものですが、本当は他の方が答えているようにハッシュではなく配列で処理するのが遥かに素直です。

    キャンセル

  • 2018/07/20 18:28

    ご丁寧に教えていただきましてありがとうございました。
    教えていただいたやり方を理解できず、コメントで頂いたように配列にして並び替えることができました。

    キャンセル

+1

まず、実際のデータが全角数字なら、半角数字に修正してください。
これは適当なエディタかなにかで実行出来るかと思います。
後述のスクリプト内に埋め込む事も出来ますが、割愛します。
あと、質問のコードに書かれている $DateTimeなどは例に出されたセルには
存在していないため、回答コードでは考慮していません。

で、半角数字に直した data.txt を相手にするとして。

|100|101|10|
|100|102|5|
|100|103|1|
|90|101|15|
|90|102|4|
|80|101|8|
|80|102|7|

要望は、「|区切りの、3最後のセルで数字の降順ソートしたい。」に簡略化されますので、
以下の script.pl で実現できます。

#!/usr/bin/env perl
my @d ;
open my $fh, '<', 'data.txt' ;
while(<$fh>){ push @d, [ $_, split /\|/, $_ ] ; }
close $fh ;
print $_->[0] for sort { $b->[4] <=> $a->[4] } @d;
$ perl script.pl
|90|101|15|
|100|101|10|
|80|101|8|
|80|102|7|
|100|102|5|
|90|102|4|
|100|103|1|

やってることは、

  1. それを元データと、セルに分割した文字列を配列に入れる push @d, [ $_, ... ] ;
  2. 3セル目で降順ソート(二次元配列上では5カラム目) sort { $b->[4] <=> $a->[4] }
  3. 元データをプリント print $_->[0]

です。

必要でないなら、ハッシュなどを使わずに、シンプルに実行するのはいかがでしょうか。
もし、記載外で他のセルが処理に必要なら、最終行の for 文を丁寧に書けば良いかと思います。

for my $r (  sort { $b->[4] <=> $a->[4] } @d ){
    my $ori = $r->[2] ;
    my $des = $r->[3] ;
    my $tot = $r->[4] ;
    ...
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/20 18:34

    ありがとうございました。
    配列でやることをご指摘いただき、何とか思ったような処理に辿り着きました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Linux

    4053questions

    Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

  • CSV

    712questions

    CSV(Comma-Separated Values)はコンマで区切られた明白なテキスト値のリストです。もしくは、そのフォーマットでひとつ以上のリストを含むファイルを指します。

  • Perl

    465questions

    Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。