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

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

新規登録して質問してみよう
ただいま回答率
85.48%
CSV

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

Perl

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

Q&A

解決済

2回答

901閲覧

perlで、 一方のcsvファイルの範囲に該当するデータをもう一方のcsvファイルから抽出したい

soso

総合スコア12

CSV

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

Perl

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

0グッド

0クリップ

投稿2018/08/16 05:51

編集2018/08/16 07:19

perlを使用して、test5_2.csvのA列とtest5.csvのA列が一致した中から、test5_2.csvにあるD列からE列の範囲(D以上E以下もしくはE以上D以下)に、test5.csvのD列もしくはE列が該当するデータをtest5.csvから抽出したいのですが、思ったように結果が出せない状況です。良い方法をご教示できないでしょうか。
test5_2.csv
A,B,C,D,E
1,総武線,上り,5,0
2,総武線,下り,0,14.24
12,京葉線,下り,0.58,0
15,京葉線,上り,0,0.43
3,新京成線,上り,4.38,0
4,新京成線,下り,4.27,4.5
5,京成線,上り,8,0
6,京成線,下り,0,13.97
5,京成線,上り,0.38,0.97

test5.csv
A,B,C,D,E
1,総武線,上り ,0,3,
1,総武線,上り ,4,25,
1,総武線,上り ,52,57,
1,総武線,上り ,65,78,
2,総武線,下り ,0,119,
12,京葉線,下り ,0,5,
15,京葉線,上り ,4,0,
3,新京成線,上り ,0,43,
4,新京成線,下り ,42,0,
5,京成線,上り ,100,137,
6,京成線,下り ,78,78,
6,京成線,下り ,78,78,

use strict; use warnings; use Text::ParseWords; use encoding 'euc-jp'; use open IN => ":encoding(cp932)"; open (FILE, 'test5_2.csv') or die "$!"; my @train; #my @match; my @D2; my @E2; my @A2; while(my $line = <FILE>){ my($A2, $B2, $C2, $D2, $E2) =split(',', $line); $B2 =~ s/\s+//; $C2 =~ s/\s+//; push(@D2,$D2); push(@E2,$E2); push(@A2,$A2); } close(FILE); open (FILE, 'test5.csv') or die "$!"; while(my $line = <FILE>){ my ($A, $B, $C, $D, $E) =split(',', $line); my $DD = $D/10; my $EE = $E/10; $B =~ s/\s+$//; $C =~ s/\s+//; foreach my $a2(@A2){ if($a2 eq $A){ foreach my $d2(@D2){ foreach my $e2(@E2){ if($d2<=$DD && $DD<=$e2){ push(@train,$A.','.$B.','.$C.','.$DD.','.$EE); } elsif($e2<=$DD && $DD<=$d2){ push(@train,$A.','.$B.','.$C.','.$DD.','.$EE); } elsif($d2<=$EE && $EE<=$e2){ push(@train,$A.','.$B.','.$C.','.$DD.','.$EE); } elsif($e2<=$EE && $EE<=$d2){ push(@train,$A.','.$B.','.$C.','.$DD.','.$EE); } } } } } } close(FILE); ##################################### # @trainの中で重複している項目を削除 # ####################################3 my %count; @train = grep(!$count{$_}++, @train); @train = sort @train; print join("\n", @train)."\n";

現状では以下のような結果になります。
1,総武線,上り,0,0.3
1,総武線,上り,0.4,2.5
1,総武線,上り,5.2,5.7 ×
1,総武線,上り,6.5,7.8 ×
12,京葉線,下り,0,0.5
15,京葉線,上り,0.4,0
2,総武線,下り,0,11.9
3,新京成線,上り,0,4.3
4,新京成線,下り,4.2,0 ×
5,京成線,上り,10,13.7 ×
6,京成線,下り,7.8,7.8

本来は上記の×の行が該当せずに以下のような結果にしたいと考えています。
1,総武線,上り,0,0.3
1,総武線,上り,0.4,2.5
12,京葉線,下り,0,0.5
15,京葉線,上り,0.4,0
2,総武線,下り,0,11.9
3,新京成線,上り,0,4.3
6,京成線,下り,7.8,7.8

説明不足の点も多々あるかと思いますが、何卒よろしくお願いいたします。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KojiDoi

2018/08/16 06:47

条件が良く分かりません。 "test5_2.csvにあるD列からE列の範囲(D以上E以下もしくはE以上D以下)に、test5.csvのA列が一致してなおかつ、D列もしくはE列が該当する" という事ですが続く例示はそのようになっている様には見えません。
KojiDoi

2018/08/16 07:09

test5.csvの数値は10で割って評価しろという事ですか?その辺をハッキリ書いておいてほしいです。
soso

2018/08/16 07:21

説明不足ですみません。10で割って評価するということです。
guest

回答2

0

#!/usr/bin/env perl my %h ; my %seen ; while (<>) { my @F = split /,/; if ($ARGV =~ /_/) { $h{$F[0]} = [sort {$a <=> $b} @F[3, 4]]; next; } next if $seen{$_}++ ; @F[3, 4] = map({$_ / 10;} @F[3, 4]); print join(',', @F) if grep {$F[$_] <= $h{$F[0]}->[1] and $F[$_] >= $h{$F[0]}->[0];} 3, 4; }

test5_2.csv test5.csv の順に引数に与えて実行してください。

$ perl test.pl test5_2.csv test5.csv 1,総武線,上り,0,0.3, 1,総武線,上り,0.4,2.5, 2,総武線,下り,0,11.9, 12,京葉線,下り,0,0.5, 15,京葉線,上り,0.4,0, 3,新京成線,上り,0,4.3, 6,京成線,下り,7.8,7.8,

標準入力のデータが、test5_2.csv の時は(if ($ARGV =~ /_/) )ハッシュテーブルを作成し
それ以外の時は、D か E のどちらかがハッシュテーブルの範囲内だった時点で 、プリントする形としています(print ... if grep ....)。

next if $seen{$_} ++ ; は重複除外の制御文です。

投稿2018/08/16 10:41

bunzaemon

総合スコア118

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

soso

2018/08/18 13:09

ご丁寧に回答いただきましてありがとうございます。 シンプルで非常に勉強になりました。 またよろしくお願いいたします。
guest

0

ベストアンサー

アルゴリズムに根本的な問題がありそうです。
とりあえずサンプルを貼って置きます。

perl

1use strict; 2use warnings; 3use utf8; 4binmode STDOUT, ":utf8"; 5 6my(@test5_2, @test5); 7my(%max, %min); 8 9# データの準備 10while(<DATA>){ # test5_2.csv に相当 11 /^$/ and last; 12 push(@test5_2, $_); 13} 14while(<DATA>){ # test5.csvに相当 15 push(@test5, $_); 16} 17 18################################ 19 20# まず取得すべき値の範囲をA列のIDごとに記録しておく 21foreach (@test5_2){ 22 my(@f)=split(/,/, $_); 23 my($max, $min, $t) = ($f[3]+0, $f[4]+0, undef); 24 ($max<$min) and $t=$min,$min=$max,$max=$t; 25 $max{$f[0]} = $max; 26 $min{$f[0]} = $min; 27} 28 29# 基準に合致している行だけprintする。 30foreach (@test5){ 31 my(@f)=split(/,/, $_); 32 my($max, $min) = ($max{$f[0]}, $min{$f[0]}); 33 #print "$f[0], $max, $min\n"; 34 my($f3, $f4) = ($f[3]/10, $f[4]/10); 35 if(($min<=$f3 and $f3<=$max) or ($min<=$f4 and $f4<=$max)){ 36 print; 37 } 38} 39 40 41__DATA__ 421,総武線,上り,5,0 432,総武線,下り,0,14.24 4412,京葉線,下り,0.58,0 4515,京葉線,上り,0,0.43 463,新京成線,上り,4.38,0 474,新京成線,下り,4.27,4.5 485,京成線,上り,8,0 496,京成線,下り,0,13.97 505,京成線,上り,0.38,0.97 51 521,総武線,上り ,0,3, 531,総武線,上り ,4,25, 541,総武線,上り ,52,57, 551,総武線,上り ,65,78, 562,総武線,下り ,0,119, 5712,京葉線,下り ,0,5, 5815,京葉線,上り ,4,0, 593,新京成線,上り ,0,43, 604,新京成線,下り ,42,0, 615,京成線,上り ,100,137, 626,京成線,下り ,78,78, 636,京成線,下り ,78,78, 64

面倒なのでデータをスクリプトの中に入れ込んでしまいましたが、適当にopen, while(<>)などの組み合わせに読み替えてください。

質問文のコードでは、データの照合の際に、へんなforeachループを作ってしまって結局A列の値にかかわらずすべてのデータとの比較を試みてしまっているため、フィルタリングになっていません。%max, %minを用意して最大値最小値をまず格納しておき、これと対象データを比較するようにすれば目的が達成できます。

投稿2018/08/16 07:35

編集2018/08/16 11:41
KojiDoi

総合スコア13671

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

soso

2018/08/18 12:57

丁寧に教えていただきましてありがとうございます。 サンプル通りにやってみたらできました。自分ではたどり着かない方法で非常に勉強になりました。 何か参考にしている本などあればご教示いただけないでしょうか。
KojiDoi

2018/08/18 13:34

書籍では『プログラミングPerl』『perlクックブック』は役に立ちました。ちょっと古い本ですが、いまだにこの本にもろに書いてあるレベルのことで引っかかっている人はこのteratailの質問を見ても少なくないようですので、買う価値は十分あるでしょう。 webではperldoc.jp。座右(?)に開いておくべきウェブコンテンツとして真っ先に挙げるべきはこれでしょう。 あと、さいきんあまり更新がありませんが http://blog.livedoor.jp/dankogai/ このブログの筆者はperlの多国語対応モジュール開発の中心人物でもある凄腕の人で、この人の記事には含蓄に富んでいるものが多いです。
soso

2018/08/20 07:55

ありがとうございます。 参考にさせて頂きます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問