__DATA__を読み取り、過去読んだものと照合計算し期待する結果を出力するにはどのようにプログラムにするのが良いでしょうか?
また、もし良ければ、こういったアルゴリズム?を思いつくにはどのように勉強するのが良いでしょうか?良い方法をご存じでしたら教えて下さい。
宜しくお願い致します。
---期待する結果---
1+5+7
2+6+8
3+7+9
4+8+10
以下続く
---code.pl---
while(<DATA>){
処理;
}
__DATA__
1
2
3
4
5
6
7
8
9
10
以下続く
A 回答 (10件)
- 最新から表示
- 回答順に表示
No.10
- 回答日時:
そんなの簡単と・・思って補足やお礼を見て・・・そりゃ無理だわ。
そんな膨大なデータは読み込んで処理なんて無理です。
一行ずつ処理して、別のデータに書き出していき、それを改めて処理するとか・・
そうではなく、そのような場合はsed ストリームエディタ
sed( https://ja.wikipedia.org/wiki/Sed_(%E3%82%B3%E3% … )
を使うべきです。
【引用】____________ここから
sedは、入力を行単位で読み取り、sedスクリプトと呼ばれるシンプルな命令文に従ってテキスト変換などの編集をおこない、また行単位で出力する。基本的には照合ルールに従い場合分けをおこなうフィルタと捉えることができる。
・・・【中略】・・・
大量のテキストファイルに対して一括で定形の処理をおこなう場合に大きな威力を発揮する。正規表現に対応しており、ある条件の範囲内の文字列を探し出して処理することができる。特定の条件に合った文字列を検索し置換するなどの用途に用いる。
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ここまで[sed (コンピュータ) - Wikipedia( https://ja.wikipedia.org/wiki/Sed_(%E3%82%B3%E3% … )]より
sedの使い方は、たくさんネットに転がっている。システムにsedがあれば、Perlからsedに渡せばよい。
No.9
- 回答日時:
これ, 計算するためには少なくとも 7行分のデータは必要なんだから, 「最初の 6行はデータをためておくだけにして, 7行目から実際の処理を行う」と考えることもできる. 例えば
my @data;
for my $i (1 .. 6) {
chomp(my $line = <DATA>);
push @data, $line;
}
while (<DATA>) {
chomp;
push @data, $_;
print $data[0]+$data[4]+$data[6], "\n";
shift @data;
}
とか, ね.
ありがとうございます。
直感的に更に分かりやすい方法ありがとうございます!
カウントさせないことで更にすっきりと見やすくなりましたね。同じ事をするにも色々な方法がある物ですね。
No.8
- 回答日時:
#7です。
>コードを写経してみたのですが、
>if($lno > 7){
>shift (@temp);
>}
>が私には思いつきそうにありませんでした。
>もしよろしければ、どのような思考で作られたのか教えて頂けると幸いです。当方独学(ネットからのコピペが多い)で自分では>このアイデアを思いつきそうにありませんでした。
今回、配列内のデータを1つずつ格納し、古いデータを押し出す必要がありますが、
そのようなことを1命令で行う機能は
perlでは残念ながら(今のところは)提供されていません。
その為、1データを押し出し(shift)、その後格納(push)する必要があります。
しかし、データの押し出しは、
データが配列内に7個存在した場合のみ可能であり、その時はシフトして6個にすることが出来ます。
その為、データが1~6個の場合は、シフトしてはいけません。
となると、8行目以降の場合にシフトすることになります。よって、
if($lno>7){
shift(@temp);
}
となります。
又、配列内に7個存在した場合なので、
if (scalar(@temp) == 7){
shift(@temp);
}
でも、同じことになります。(scalar(@temp) で、@temp内の要素の数が取得できます。)
No.7
- 回答日時:
>__DATA__と書きましたのは汎用性のある処理部分の仕方を聞きたいというのが主であったためです。
実際はファイルを分けて質問すべきでした。大変失礼致しました。>ランダムと言うよりも、7行ほど先読みする程度(8や9行になることはあっても、それ以上には飛ばない程度の汎用性)ですので、データベースを使うと逆に遅くなる気がしています。DBは殆ど利用したこともなく、クエリーを発行して受け取ってなど1億行もあるとものすごく遅くなるイメージがあります。
なるほど、そのような事情でしたか。
それであれば、今回の例であれば7件分を逐次配列に格納し、それを処理するのが、良いと考えます。
但し、以下の
1+5+7
2+6+8
3+7+9
のように処理するデータは規則性があることが前提です。
先読みというよりは、7行まで読み込んだとき、そのデータを配列に溜め込んでおき、それを処理する形になります。
8行目以降は、逐次、配列のデータをシフトしていきます。
以下、サンプルソースです。
--------------------------
$lno = 0;
@temp = ();
while(<DATA>){
chomp $_;
$lno++;
if ($lno > 7){
shift(@temp);
}
push(@temp,$_);
if ($lno >= 7){
$val = $temp[0] + $temp[4] + $temp[6];
print "line=$lno val=$val\n";
}
}
__DATA__
1
2
3
4
5
6
7
8
9
10
----------------------
以下、実行結果です。
line=7 val=13
line=8 val=16
line=9 val=19
line=10 val=22
スッキリとしたコードありがとうございます。
あとで読み返しても、読みやすそうなコードですね。
コードを写経してみたのですが、
if($lno > 7){
shift (@temp);
}
が私には思いつきそうにありませんでした。
もしよろしければ、どのような思考で作られたのか教えて頂けると幸いです。当方独学(ネットからのコピペが多い)で自分ではこのアイデアを思いつきそうにありませんでした。
No.6
- 回答日時:
大量処理をするなら、メモリを大量に使用する富豪的プログラミングは厳禁です。
となると、どうしても泥臭い書き方になってしまうので、
少々読みづらくなりますがご容赦ください。
my @a;
my $i = 0;
my ($indexA, $indexB, $indexC, $r);
foreach (<DATA>) {
_ $a[$i%7] = $_; # 7要素の配列にて shift/push を一回ですませる書き方
_ $i++;
_ next if ($i < 7);
_ $indexA = ($i-7)%7; # shift を使わないで $a[0] を表わす
_ $indexB = ($i-3)%7;
_ $indexC = ($i-1)%7;
_ $r = $a[$indexA] + $a[$indexB] + $a[$indexC];
_ print $r . "\n";
}
No.5
- 回答日時:
#4です。
>ただ、この方法ですとデータ量が増えると(例えば1億行など)非常に膨大にありますと、エラーが出まして上手く処理が出来ないのです。
ということは、__DATA__のあとに、1億行があるようなスクリプトを作成されているということでしょうか?
そのようなスクリプトを作成すること自体に問題があると思いますがいかがでしょうか。
データが1億件あり、それらをランダムに処理したいということであれば、通常はデータベースに格納してそれを参照するのが一般的です。
どうしても、perl単体で(データベース等を使用しないで)行いたいということであれば、ファイルにデータを格納し、そこから
データを逐次取り出す方法があります。但し、ファイルは1データのサイズを固定(例えば10バイト)にする必要があります。
1データのサイズが固定であれば、n番目のデータを取り出すためには、読み込み位置を先頭からn番目に該当する位置にシークさせ、読み込むことが可能です。但し、毎回、ファイルにアクセスするので、処理時間は劇的に遅くなることが予想されます。
すみません。
__DATA__と書きましたのは汎用性のある処理部分の仕方を聞きたいというのが主であったためです。実際はファイルを分けて質問すべきでした。大変失礼致しました。
ランダムと言うよりも、7行ほど先読みする程度(8や9行になることはあっても、それ以上には飛ばない程度の汎用性)ですので、データベースを使うと逆に遅くなる気がしています。DBは殆ど利用したこともなく、クエリーを発行して受け取ってなど1億行もあるとものすごく遅くなるイメージがあります。
また、エラーログみたいな物ですので、データサイズは残念ながら固定ではありません。実は、Excelでやっていたのですが、データ量が増えてきたため同様のことをさせるには104万行の壁にぶちあたりPerlを使った感じです。
AccessなどDBも持っているのですが、以前質問した時、AccessではExcelのようにB1へ=A1+A5+A7を入れれば、オートフィルでスパッとは無理との話で仕方が無くperlに切り替えた感じおります。
No.4
- 回答日時:
基本的には配列に全行のデータを格納し、それをあとから参照します。
以下のようにしてください。
--------------------------------------
@line=();
while(<DATA>){
chomp $_; #改行を削除
push(@line,$_);
}
$val = $line[0]+$line[4]+$line[6]; # 1+5+7
print "$val\n"; # 結果の印字
$val = $line[1]+$line[5]+$line[7]; # 2+6+8
print "$val\n"; # 結果の印字
#以下省略
__DATA__
1
2
3
4
5
6
7
8
9
10
------------------------------
以下、実行結果です。(スクリプト名をsample.plとします)
perl sample.pl
13
16
具体的なコードを書いて頂きありがとうございます!!
連続的に出力できるよう少しこちらで書き換えてみました。ただ、この方法ですとデータ量が増えると(例えば1億行など)非常に膨大にありますと、エラーが出まして上手く処理が出来ないのです。
更に、$val = $line[0]+$line[4]+$line[6]; # 1+5+7
のような折角分かりやすい記述からも遠くなりあとで何やってるのか分からなくなってしまうことがあり困るというのもあります。書いている時には理解しているのですが、数日経ったら例えば、
unless($line[$cnt+6]){last;}
など何やってるんだろ?となったりしてしまいます。仕方のない部分はあると思いますが、可能であれば後日にでもコードを見るだけで何をやっているのか分かればと言う思いもあります。
# Windows 7 + active perl
use strict;
my @data;
for(1..100000000){
push (@data,$_); # ★Out of memory!が出る
}
# my @data = <DATA>; # ★行数が増えるとエラーになる
my @line = ();
while(@data){
chomp $_; #改行を削除
push(@line,$_);
}
my $cnt = 0;
for(;;){
unless($line[$cnt+6]){last;}
my $val = $line[$cnt]+$line[$cnt+4]+$line[$cnt+6]; # 1+5+7
print "$val\n";
$cnt++;
}
__DATA__
1
2
3
4
5
6
7
8
9
10
11
12
No.3
- 回答日時:
> 7行も離れている場合どうすれば良いのか悩んでおります。
配列を用意して、行を読むごとにpushで配列の最後に追加、7行分たまったらshiftで配列の先頭から読み出しすれば、常に7行のデータのみ保持することで対応可能です。
http://perl.misty.ne.jp/05.html#b
ありがとうございます。
7行を判定する感じでやってみました。
アドバイスを元に書いてみたのですが、数日後読み返すと、これが何をやっているのか理解できない気がしています。コメントアウト無しで、もう少しわかりやすくできない物でしょうかね?
また、特に@line = &Calc(@line);など二回現れていますし、直感的にはどうも違和感を感じています。
# Windows 7 + active perl
use strict;
my @line;
while(<DATA>){
chomp $_; #改行を削除
push(@line,$_);
@line = &Calc(@line);
}
@line = &Calc(@line);
sub Calc(){
my @line = @_;
if(@line != 8){return @line;}
unless($line[6]){return ;}
my $val = $line[0]+$line[4]+$line[6]; # 1+5+7
print "$val\n";
shift @line;
return @line;
}
__DATA__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
No.2
- 回答日時:
> whileの代わりにfor(<DATA>)を使っただけでエラーが出てしまいました
これは、単に間違った使い方をしただけのことです。
<>は、スカラーのコンテキストでは1行読み込み、リストのコンテキストでは全行読み込み1行ずつのリストになります
※ Perlを使う上で、「コンテキスト」「スカラー」「リスト」というのは、とても大事な概念です。
覚えておきましょう。
例えば
@line = <DATA> ;
とすると、 リストのコンテキストになるので、<DATA>は全ての行を読み込み、1行が一つの要素になります。
この状態では
$line[0] は 1行目
$line[1] は 2行目
...
となります。
ありがとうございます。
@line = <DATA> ;でリストになることは何となく理解しているつもりなのですが、データ量が膨大(10GB、1億行程度)もりout of memory!となってしまいました。
その為、1行ずつ読み出せるようにするには、whileを使うべきだとありこちらを試しているところなのです。
先読みを7行目までして、それを保持して順次配列をずらす必要があり、どうしたら良い物かと思っているのです。
因みに、1文字ずらし計算するだけであれば、$tempを使いよくするのですが7行も離れている場合どうすれば良いのか悩んでおります。
while(<DATA>){
if($temp){
print $_ + $temp;
}
$temp = $_;
}
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# 1. 仮想CPU「exmini」を使用して,「$dataからn減算する」プログラムを作成してください 2 2022/07/04 17:49
- Visual Basic(VBA) 列と行の名前(重複あり)が交差するセルに、データを入力したい 2 2022/06/25 22:42
- C言語・C++・C# pythonのファイルの並びでの読み込みとリストについて 4 2022/04/13 03:52
- Excel(エクセル) 何方か知恵をください… 下記のシート1にシート2のDATAを表示させたいです。 (シート1の2行目の 6 2022/03/28 17:27
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- システム CPUの問題について 2 2022/07/09 12:04
- その他(プログラミング・Web制作) Python - Excel で Webからデータを連続取得したいのですが エラーが出ます 1 2023/07/06 20:08
- C言語・C++・C# C言語 3 2022/10/04 15:07
- Excel(エクセル) 【Excel質問】別シートにある複数の同型の表から、同じ行項目にある数字を集計する 4 2023/02/16 00:14
- Excel(エクセル) PHPプログラムをエクセルに張り付けると検索ボックスがでてくる! 3 2022/05/08 07:10
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Perlのサンプルを見ていると
-
配列の中に重複文字列があるか...
-
無名配列からハッシュを作りた...
-
csvで順番の入れ替え
-
VBAでCSVファイルの特定行を書...
-
Perlの変数に文字数制限(容量...
-
VBAでCSVファイルを途中行まで...
-
awkスクリプトでダブルクォーテ...
-
ExcelをCSV書き出す場合のシー...
-
Firefox で file:// で始まる U...
-
DOSコマンドで、標準出力を出力...
-
python renameについて
-
ファイル出力の改行コードをLFに
-
C言語で特定の行を抽出する方法...
-
[Perl]ファイル出力のエンコー...
-
htaccessで特定のディレクトリ...
-
巨大なテキストの最終行を取得...
-
drtファイルはどうしたら開...
-
sprintfについて
-
無料配布の郵便番号自動入力cgi...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
どのようなプログラムをつくれ...
-
perlでの三次元配列の作り方
-
csvで順番の入れ替え
-
配列の中に重複文字列があるか...
-
pushをすると行ができる
-
要素を削除する最適な方法
-
perlで複数行のデータを自由に...
-
Perlの初歩的な質問・・・
-
行・列の整理! perl
-
ファイルから読み込んで配列へ
-
perl-cgi 文字の長さでソートし...
-
Pythonの再帰関数の動作の流れ...
-
C言語のバイナリモードでのfsca...
-
C言語でバイナリファイルの読み...
-
ランダムでかぶらないように4...
-
perlで読み込んだURLを配列に入...
-
CSVデータ「","」と「,」混在読...
-
perlの無名配列の使い方を教え...
-
ソートのテクニックについて
-
@の配列変数ではなく$のスカラ...
おすすめ情報