はじめまして、皆様のお知恵を拝借したく投稿しました。
よろしくお願いします。

perlでのデータ処理で入力ファイルが
---------------------------------
start end
1 4
6 10
12 16
14 20
22 25
---------------------------------
となっている場合、4行目の開始位置が3行目の終了位置よりも
前になっているデータがあるとします。
(領域14~16までが領域が重複しているという意味です)。

この重複している領域部分を統合して
---------------------------------
start end
1 4
6 10
12 20
22 25
---------------------------------
と再出力できるようにperlでコーディングしたいのですが
どのようにしたらよいのでしょうか?

ご助言いただけますと幸いです

このQ&Aに関連する最新のQ&A

A 回答 (2件)

単に「ある区間の開始位置が別の区間の終了位置より前にあったら (適切に) マージする」だけかなぁ? 動いているような気はするけどちょっと不安. あと, 「区間」の考え方によっては変更が必要です.



#!/usr/bin/perl
my @ranges = (
[1, 4],
[6, 10],
[12, 16],
[14, 20],
[22, 25],
);

my @results;

@ranges = sort { $a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] } @ranges;

my $theRange = shift @ranges;
for my $range (@ranges) {
if ($theRange->[1] < $range->[0]) {
push @results, $theRange;
$theRange = $range;
} elsif ($theRange->[1] < $range->[1]) {
$theRange->[1] = $range->[1];
}
}

push @results, $theRange;

for my $range (@results) {
print "$range->[0] $range->[1]\n";
}
    • good
    • 0
この回答へのお礼

なるほど、二次元配列を使う手があるのは気がつきませんでした。
早速のご回答ありがとうございます。

ご参考の意見を基に早速試してみます。
取り急ぎ御礼まで

お礼日時:2007/12/18 22:15

start と end の中間の数字も1つの配列に入れ、並べ替えて、隣り合う2つの数字を比較して、


差が 2 以上ある場合は、前の数字を範囲の終わり、後の数字を範囲の始まりとして出力しています。

use strict;
my @list = (1 .. 4, 6 .. 10, 12 .. 16, 14 .. 20, 22 .. 25);
@list = sort { $a <=> $b } @list;
print "$list[0] ";
my $p = $list[0];

foreach my $n (@list[1 .. $#list]) {
print "$p\n$n " if $n - $p >= 2;
$p = $n;
}

print "$list[$#list]\n";
    • good
    • 0
この回答へのお礼

なるほど、こんなにシンプルにまとめられることもできるんですね。
まったく思いつきませんでした

ありがとうございます

お礼日時:2007/12/19 10:02

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

このQ&Aと関連する良く見られている質問

QPerlでハッシュや配列で重複するキーについて

ハッシュで重複するキーが値となるので、このハッシュはabdの3つのキーしか存在しないということでしょうか?
%a = ('a'=>1, 'b'=>2, 'a'=>3, 'd'=>4);

また、配列の場合はabadと4つ数になるということでしょうか?
@a = ('a','b','a','d');

この場合配列で、重複する値を抽出するアルゴリズムが知りたいです。

Aベストアンサー

重複のチェックはこんな感じでいいでしょう。

@a = ('a', 'b', 'a', 'd');

for (@a) {
  if (defined $hash{$_}) {
    print $_, "が重複してます。\n";
    next;
  }
  $hash{$_} = 1;
}

QPerl。文字出現回数を重複しないでカウントしたい。

perl初心者です。どうぞ助けて下さい。
以下のようにデータがならんでいる時、

pphhhppphhhppppppphhppppppppppppppppppphhh

pが連続した文字の連続数は
2、3、7、19
となります。

今、知りたいのはこのようなpの連続数の出現回数です。つまり、たとえばpが19回連続してあるものは何回でてきたか、が知りたいのです。
上の例だと1回が正解となります。
ところが、スクリプトを書くとき、
たとえば以下のようにしたとき、
pが19回なら重複カウントはなくても、
pを2でカウントしたら、
本当に出てきて欲しいこたえは一回なのに、
P=3、7、19のどれにも該当してしまいます。

#!/usr/bin/perl ;
open(IN, "text1.txt") or die ;

open(OUT, ">text1out.txt");

while(<IN>) {
chomp ;
if (/(\S+)/) {

$name = $1 ;

if ($name =~ /^ppppppppppppppppppp/) {
{$count++;}
;

}
print OUT "$count\n" ;
}
}
close (IN) ;
close (OUT) ;

正規表現の中を工夫すればいいのだと思いますが、


大変困っております。宜しくお願いします。

perl初心者です。どうぞ助けて下さい。
以下のようにデータがならんでいる時、

pphhhppphhhppppppphhppppppppppppppppppphhh

pが連続した文字の連続数は
2、3、7、19
となります。

今、知りたいのはこのようなpの連続数の出現回数です。つまり、たとえばpが19回連続してあるものは何回でてきたか、が知りたいのです。
上の例だと1回が正解となります。
ところが、スクリプトを書くとき、
たとえば以下のようにしたとき、
pが19回なら重複カウントはなくても、
pを2でカウントしたら、
...続きを読む

Aベストアンサー

アバウトな実装ですが、こんなんとか:

> cat a.pl
$_ = 'pphhhppphhhppppppphhppppppppppppppppppphhh';
while ( s/^(.)\1*// ){ $char_map{$1}{ length( $& ) }++; }
foreach $c ( sort keys %char_map ){
%char_len_map = %{$char_map{ $c }};
foreach $n ( sort keys %char_len_map ){ print $c,' ', $n, ' ', $char_len_map{ $n }, "\n"; }
}

以下が実行結果:
> perl a.pl
h 2 1
h 3 3
p 19 1
p 2 1
p 3 1
p 7 1

ポイントは、tasekiさんがアドバイスしているように、「連続数が何個あるか」という問題を、
step.1)連続する文字列毎に切り出す。
step.2)切り出した文字列の、文字種と文字列長をカウントする。
という問題に分割して解決してるところ。

アバウトな実装ですが、こんなんとか:

> cat a.pl
$_ = 'pphhhppphhhppppppphhppppppppppppppppppphhh';
while ( s/^(.)\1*// ){ $char_map{$1}{ length( $& ) }++; }
foreach $c ( sort keys %char_map ){
%char_len_map = %{$char_map{ $c }};
foreach $n ( sort keys %char_len_map ){ print $c,' ', $n, ' ', $char_len_map{ $n }, "\n"; }
}

以下が実行結果:
> perl a.pl
h 2 1
h 3 3
p 19 1
p 2 1
p 3 1
p 7 1

ポイントは、tasekiさんがアドバイスしているように、「連続数が何...続きを読む

QPerl テキスト 重複 個数

ある書込ファイルでの重複した場合の処理・・・

~text.txt~
1490747427,あ,あ,あ,SrZqgZAs,1234
1490747417,あ,あ,あ,SrZqgZAs,1234
1490747071,7,7,7,SrZqgZAs,777
1490747041,6,6,6,SrZqgZAs,1234
1490747025,5,5,5,SrZqgZAs,1234

(左から「time,name,title,text,id,password」の順で並んでいます。)

今回、教えていただきたいことが、

次に入力する値が

name = あ
id = SrZqgZAs

だった場合に、text.txtに
すでに入力する値が、2回あるため
入力できないようにしたいのです。

そこで、
text.txt内にある
name(あ) と id(SrZqgZAs) の個数を数える
方法をご教示お願い致します。

※()内のnemeは
my $NAME = $form->param('name');
と、CGI.pmで受け取った値

idは
$ID = (※IPアドレスと時間による自動整正したソース)

ある書込ファイルでの重複した場合の処理・・・

~text.txt~
1490747427,あ,あ,あ,SrZqgZAs,1234
1490747417,あ,あ,あ,SrZqgZAs,1234
1490747071,7,7,7,SrZqgZAs,777
1490747041,6,6,6,SrZqgZAs,1234
1490747025,5,5,5,SrZqgZAs,1234

(左から「time,name,title,text,id,password」の順で並んでいます。)

今回、教えていただきたいことが、

次に入力する値が

name = あ
id = SrZqgZAs

だった場合に、text.txtに
すでに入力する値が、2回あるため
入力できないようにしたいのです。...続きを読む

Aベストアンサー

以下のようになります。
----------------------------
my $datafile="text.txt";
my $name = "あ";
my $id = "SrZqgZAs";
my $name_ctr = 0;
my $id_ctr = 0;
open(FH, $datafile);
while(<FH>){
chomp($_);
my ($time0,$name0,$title0,$text0,$id0,$pass0) = split(/,/,$_);
if ($name eq $name0){ $name_ctr++; }
if ($id eq $id0){ $id_ctr++; }
}
close(FH);
print "name_ctr=$name_ctr\n";
print "id_ctr=$id_ctr\n";
------------------------------------
以下、実行結果です。
name_ctr=2
id_ctr=5

QPerlでの重複要素カウントについての質問

Perlのデータ処理に関する質問です。

afcb7dc0,"福岡県","天神","福岡県","博多・福岡空港"
09f115fc,"東京都","東急沿線","東京都","東急沿線","東京都","代官山、恵比寿-五反田","東京都","東急沿線","東京都","三田、浜松町-品川","東京都","東急沿線"
3933245b,"東京都","新宿・代々木"
・・・

という形式のCSVファイルがあるときに、これを

afcb7dc0,"福岡県",2,"天神",1,"博多・福岡空港",2
09f115fc,"東京都",6,"東急沿線",4,"代官山、恵比寿-五反田",1,"三田、浜松町-品川",1
3933245b,"東京都",1,"新宿・代々木",1

の形式に変換するにはどうすればいいでしょうか?
ご教授願います。

Aベストアンサー

それなら例えば
while (my $line = <>) {
chomp $line;
my ($id, @data) = split /,/, $line;
my %count;
my @item;
for (@data) {
push @item, $_ unless $count{$_}++;
}
print $id;
for (@item) {
print ",$_,$count{$_}";
}
print "\n";
}
とかでどうだろ.

QPerlでファイルを読み込み重複データの検索

お世話になります。
次のようなテキストファイルを読み込んで重複を探し、表示したいのですが、Perlで、どのようなコードを書けば良いのでしょう。

尚、重複チェックは2通りあります。
パターン1 例えば1,2が2回以上出現する
パターン2 1,2と2,1や2,3と3,2は重複とみなす。

テキストファイル
1,2
1,3
1,4
1,5
2,1
2,3
2,4
2,5
3,1
3,2
1,2

チェック後の表示
1,2,重複
1,3,重複
1,4,
1,5,
2,1,重複
2,3,重複
2,4,
2,5,
3,1,重複
3,2,重複
1,2,重複

宜しくお願いします。

Aベストアンサー

解説:
while(<DATA>){#実際は、ファイルハンドル(か<>)になるべき所、DATAにしておくと、__END__から読み込める、この場合は、別にテキストファイルを作るのがめんどくさかったからと、これだけで実行(追試)ができるという意味
chomp;#末尾の改行を切り捨てる、引数が無い時は$_現在の読み込み行に対して実行される
$data[$i++]=$_;#現在の行を、あとで元データとして利用するために配列に入れておく
$test{$_}++;#既にあったかどうかテストするために行データをキーにハッシュにしておく、値は、出現回数
($a, $b)=split ",";#今読み込んでる行を「,」で分離する
$test{"$b,$a"}++;#逆順の並びでハッシュに登録
}
foreach $x (@data){#元のデータを順に取り出す
print "$x";#オリジナルの表示
print ",重複" if($test{$x}>1);#ハッシュで、2回以上カウントされていたら重複しているって表示する
print "\n";#改行をつけて一行分処理終わり
}
__END__

解説:
while(<DATA>){#実際は、ファイルハンドル(か<>)になるべき所、DATAにしておくと、__END__から読み込める、この場合は、別にテキストファイルを作るのがめんどくさかったからと、これだけで実行(追試)ができるという意味
chomp;#末尾の改行を切り捨てる、引数が無い時は$_現在の読み込み行に対して実行される
$data[$i++]=$_;#現在の行を、あとで元データとして利用するために配列に入れておく
$test{$_}++;#既にあったかどうかテストするために行データをキーにハッシュにしてお...続きを読む


おすすめ情報