[PERL] 동일 열의 연속값의 누적합과, 그 열의 누적값중에서의 최대값 산출하기

momo7의 이미지

안녕하세요. 기상자료를 분석하는데 조금 안 풀리는 부분이 있어서 질의드립니다.

365일 동안 연속적으로 비가 안오는 날의 최대값을 산출하는 문제를 해결하고자 아래와 같은 코드를 작성했습니다.

먼저 비가 안오는 날은 1, 비가 오는 날은 0으로 해서 해당일이 비가 오면 앞날의 값에 1을 더하고,

비가 오지 않으면 그 값을 0으로 처리하여 값이 누적되게 1번째 코드를 작성하였습니다.

그 이후에 같은 열을 비교하여 가장 값이 큰 값을 산출하도록 2번째 코드를 작성하였습니다.

문제는 제가 최대값만을 최종생산물로 원하고 누적값은 중간생성물파일로 저장하지 않고 메모리에서 한번에 처리하고자 하는데

하나로 묶는데서 해결이 되지 않아 도움을 요청합니다. 해안을 부탁드립니다.

예시 데이터는 아래와 같습니다.

(원본 데이터)
1 1 2 0 0 1 0 1
1 1 2 0 0 1 1 0
2 1 2 0 1 2 0 1
1 1 0 1 0 1 0 1

(누적값 도출)
0 0 0 1 1 0 1 0
0 0 0 2 2 0 0 1
0 0 0 3 0 0 1 0
0 0 1 0 1 0 2 0

(최대값)
0 0 1 3 2 0 2 1

# 첫번째 코드
#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
my (@buf,$sum,%sum,@sum);

while(<>){
@buf = map { ($_== 0)?1:0 } split;
for (my $j=0; $j<=$#buf; $j++){
if ($buf[$j] == 1) {$sum{$j} += 1;}
elsif ($buf[$j] == 0) {$sum{$j} = 0;}
print (($sum{$j})," ");
}
print "\n";
}

# 두번째 코드
use 5.010;
use strict;
use warnings;

my (@arr, %arr, $row);
while(<>){
@arr=split;
for (my $i=0; $i<=$#arr; $i++){
$arr{$i} = $arr[$i] if ($arr[$i] >= $arr{$i});
}
$row++;
}

print (($arr{$_})," ") for (sort {$a <=> $b} keys (%arr));
print "\n";

익명 사용자의 이미지

저도 모르지만... 나름 2 시간정도 찾아서 만든겁니다. ㅡ_ㅡ;;

해답은 아니지만. 잘 실행 됩니다.
입력을 2 개만 가능하게 되어 있는데. 중요한건 저런 방식으로 구현이 가능하다는거니까요.
실행 되는 기능을. 참고만 해보시기 바랍니다.

#!/usr/bin/perl
 
# 샵은 주석
# 설치 방법 : <a href="http://learn.perl.org/first_steps/
 
#" rel="nofollow">http://learn.perl.org/first_steps/
 
#</a> 첫번째 코드
use 5.010;						# 버전
use strict;						# 문법 오류 체크
use warnings;						# 오류 알림
 
 
# @list = ("abc", "def", "123");			리스트
# %hash = (('test', "hello"), ('verify', 123));		해시
 
# <a href="http://cafe.naver.com/q69/120699?social=1
#" rel="nofollow">http://cafe.naver.com/q69/120699?social=1
#</a> while(<>)
 
# 2번 입력 엔터를 2번 반복.
my (@buf,$sum,%sum,@sum);				# 변수 선언	<a href="http://cafe.naver.com/perlstudy/20
 
#" rel="nofollow">http://cafe.naver.com/perlstudy/20
 
#</a> 리스트에 값 넣고 빼는걸 몰라서. 그냥 한줄 배열로 사용함. ㅡ_ㅡ;;
my $max		= 2;					# 한줄에 입력되는 갯수
my $input_cnt	= $max * 2;				# 입력된 총 갯수. 2줄
my @list;
my %hash;
 
my $cnt = 0;
sub fn1(@)
{
	my $t = 0;
#	my $input = $_[0];				# 뭔지 모름
 
	while(<>)
	{
#		@buf = <STDIN>;
#		chomp( @buf = <STDIN> );
 
#		@buf = map { ($_== 0)?1:0 } split;	# 입력 받는다 <a href="http://blog.daum.net/jchern/13756909
" rel="nofollow">http://blog.daum.net/jchern/13756909
</a>		@buf = split;				# 입력 받는다 <a href="http://blog.daum.net/jchern/13756909
" rel="nofollow">http://blog.daum.net/jchern/13756909
</a>							# @buf 리스트에 받는다
#		print ((@buf),"\n"); 			# 출력
		for (my $j=0; $j<=$#buf; $j++)		# j는 0부터 $#buf 까지. 받는다.
							# $# 는 @buf 리스트에 마지막 인덱스다. <a href="http://blog.naver.com/kbsps?Redirect=Log&logNo=120027753274
" rel="nofollow">http://blog.naver.com/kbsps?Redirect=Log&logNo=120027753274
</a>		{
			if ($buf[$j] == 1)		# 1이면 $sum{$j} 증가
			{
#				$sum{$j} += 1;
			}
			elsif ($buf[$j] == 0)		# 0이면 $sum{$j} 0
			{
#				$sum{$j} = 0;
			}
#			print (($sum{$j})," "); 	# 출력
#			@list[$j][$t] = $sum{$j};
#			@list = (@list, $buf[$j]);	# 이거 때문에 값이 중복 들어갈 수 있으니 주의하자
 
			$sum{$j} = $buf[$j];
 
#			print (@list); 			# 출력
#			print (($buf[$j])," "); 	# 출력
#			print (($sum{$j})," "); 	# 출력
#			$list{$cnt} = $buf[$j];
			push(@list, $buf[$j]);		# <a href="http://blog.naver.com/illi0001?Redirect=Log&logNo=140118574584
" rel="nofollow">http://blog.naver.com/illi0001?Redirect=Log&logNo=140118574584
</a>			$cnt += 1;
		}
 
#		print ("total = ", ($t), "\n"); 	# 출력
		$t += 1;
 
		if($t == $max)				# 0 1 합계 2번
		{
#			last;				# 종료 문구
		}
		last if ($t == $max);
	}
}
fn1();
 
 
print ("입력 완료\n");
# exit;
 
 
$cnt = 0;
sub fn2(@)
{
	my $t = 0;
	my $r = 0;
 
#	인수로 명령 줄에 전달 된 실제 모든 파일
#	real all files passed by command line as a arguments
#	while(<>)					# <a href="http://blog.naver.com/miniwikibook?Redirect=Log&logNo=60137757521
" rel="nofollow">http://blog.naver.com/miniwikibook?Redirect=Log&logNo=60137757521
</a>	while( $cnt < $input_cnt )
	{
#		for (my $j=0; $j<$max; $j++)		# j는 0부터 $#buf 까지. 받는다.
							# $# 는 @buf 리스트에 마지막 인덱스다. <a href="http://blog.naver.com/kbsps?Redirect=Log&logNo=120027753274
" rel="nofollow">http://blog.naver.com/kbsps?Redirect=Log&logNo=120027753274
</a>		{
#			$r = pop(@list);
			print ($list[$cnt], " ", $cnt, " ");	# 출력
#			shift(@list);
			$cnt += 1;
		}
		print ("\n");
 
		if($cnt < $max - 1)			# 0 1 합계 2번
		{
			exit;			# 종료 문구
		}
#		$t += 1;
#		last if ($t == $max);
	}
}
fn2();
 
 
print ("입력값/ 카운터 - 출력 완료\n");
 
 
 
$cnt = 0;
sub fn3(@)
{
	my $t = 0;
	my $r = 0;
 
	open (WFILEHANDLE, ">test.txt") or die ("Cannot open test.txt .\n");
 
#	인수로 명령 줄에 전달 된 실제 모든 파일
#	real all files passed by command line as a arguments
#	while(<>)					# <a href="http://blog.naver.com/miniwikibook?Redirect=Log&logNo=60137757521
" rel="nofollow">http://blog.naver.com/miniwikibook?Redirect=Log&logNo=60137757521
</a>	while( $cnt < $input_cnt )
	{
#		for (my $j=0; $j<$max; $j++)		# j는 0부터 $#buf 까지. 받는다.
							# $# 는 @buf 리스트에 마지막 인덱스다. <a href="http://blog.naver.com/kbsps?Redirect=Log&logNo=120027753274
" rel="nofollow">http://blog.naver.com/kbsps?Redirect=Log&logNo=120027753274
</a>		{
#			$r = pop(@list);
			print WFILEHANDLE ($list[$cnt], " ", $cnt, " ");	# 출력
#			shift(@list);
			$cnt += 1;
		}
		print WFILEHANDLE ("\n");
 
		if($cnt < $max - 1)			# 0 1 합계 2번
		{
			exit;			# 종료 문구
		}
#		$t += 1;
#		last if ($t == $max);
	}
	close(WFILEHANDLE);
}
fn3();
 
 
print ("파일 저장 완료\n");
 
 
 
# <a href="http://pc-to-mac-changer.blogspot.kr/2012/12/perl-file-test-operators.html
#" rel="nofollow">http://pc-to-mac-changer.blogspot.kr/2012/12/perl-file-test-operators.html
#</a> <a href="http://www.comp.leeds.ac.uk/Perl/filehandling.html
#" rel="nofollow">http://www.comp.leeds.ac.uk/Perl/filehandling.html
#</a> <a href="http://www.cs.cf.ac.uk/Dave/PERL/node70.html
#" rel="nofollow">http://www.cs.cf.ac.uk/Dave/PERL/node70.html
#</a> <a href="http://www.cs.cf.ac.uk/Dave/PERL/node72.html#SECTION001032000000000000000
#" rel="nofollow">http://www.cs.cf.ac.uk/Dave/PERL/node72.html#SECTION001032000000000000000
#</a> <a href="http://sunshowers.tistory.com/51
 
 
 
#" rel="nofollow">http://sunshowers.tistory.com/51
 
 
 
#</a> <a href="http://nobless_05.blog.me/50095113724
$cnt" rel="nofollow">http://nobless_05.blog.me/50095113724
$cnt</a> = 0;
sub fn4(@)
{
	my $file = "test.txt";
	my $line;
	my $fh;
 
#	open ($fh, "<test.txt") or die ("Cannot open test.txt .\n");
	open ($fh, "<", $file) or die ("Cannot open test.txt .\n");
 
	while( $line=<$fh> )
	{
		print $line;
	}
	close($fh);
}
fn4();
 
 
print ("파일 보기 완료\n");
 
 
//출력 결과
1 2
3 4
입력 완료
1 0
2 1
3 2
4 3
입력값/ 카운터 - 출력 완료
파일 저장 완료
1 0
2 1
3 2
4 3
파일 보기 완료

momo7의 이미지

많은 시간 저를 위해 투자해 주셔서 감사합니다. 차근차근 해석해가며 적용해 보겠습니다.

shint의 이미지

ㅡ_ㅡ;; 저도 필요한 내용일 수 있거든요...

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

qiiiiiiiip의 이미지

먼저 비가오는 날에 대한 raw파일을 아래와 같은 형태로 만들고,

$ cat data.txt
101001010101000100101110010100010101111111101111110001111001010

여기서 연속된 1의 개수를 count하는 방법으로 할 듯..
예를 들어 아래처럼

$ perl -pe 's,(1+),length($1),ge' data.txt  | tr -s '0' ','
1,1,1,1,1,1,1,1,3,1,1,1,1,8,6,4,1,1,

최대값 하나만 찾고 싶다면

$ perl -pe 's,(1+),length($1),ge' data.txt  | tr -s '0' '\n' | sort -n | tail -n 1
8
momo7의 이미지

(원본 데이터)
서울 대구 부산 .....
1일 1 1 2 0 0 1 0 1
2일 1 1 2 0 0 1 1 0
3일 2 1 2 0 1 2 0 1
4일 1 1 0 1 0 1 0 1

(누적값 도출)
서울 대구 부산 .....
1일 0 0 0 1 1 0 1 0
2일 0 0 0 2 2 0 0 1
3일 0 0 0 3 0 0 1 0
4일 0 0 1 0 1 0 2 0

(최대값)
서울 대구 부산 .....
연속최대일 0 0 1 3 2 0 2 1

qiiiiiiiip의 이미지

컬럼이 지역별이었군요..
그럼 지역별로loop돌면서 컬럼별로 연속된 0의 개수를 카운트하는 문제겠네요..

$ cat data.txt
서울 대구 부산 .....
1일 1 1 2 0 0 1 0 1
2일 1 1 2 0 0 1 1 0
3일 2 1 2 0 1 2 0 1
4일 1 1 0 1 0 1 0 1
 
$ for col in `seq 2 8`; do tail -n +2 data.txt | cut -f $col -d ' ' | tr -d '\n' | tr '[1-9]' x | perl -pe 's,(0+),length($1),ge' | tr -s 'x' '\n' | sort -n | tail -1 | perl -pe 's,^$,0,' | tr -s '\n' ' ' ; done
0 0 1 3 2 0 2 

momo7의 이미지

님 아이디어를 바탕으로 다음과 같이 코드를 작성하였습니다. 한줄코드는 제가 이해를 잘 못해서.. 다시 작성했습니다.

#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
my (%total,@total,$total,@buf,$sum,%sum);
my (@arr, %arr, $row);
 
# 각 날짜별 누적 무강우 일수 도출
 
while(<>){
  @buf = map { ($_== 0)?1:0 } split;
    for (my $j=0; $j<=$#buf; $j++){
      if ($buf[$j] == 1) {$sum{$j} += 1;}
      elsif ($buf[$j] == 0) {$sum{$j} = 0;}
      push @total, $sum{$j};
    }
}
 
# 각 공간별 최대값 도출
for (my $k=1; $k <= $.; $k++){
  for (my $i=0; $i<=$#buf; $i++){
    if ($k == 1){
      $arr[$i] = shift(@total);
      $arr{$i} = $arr[$i]
    } 
    elsif ($k != 1){
      $arr[$i] = shift(@total);
      $arr{$i} = $arr[$i] if ($arr[$i] >= $arr{$i});
    }
  }
}
 
print (($arr{$_})," ") for (sort {$a <=> $b} keys (%arr)); 
print "\n";

익명 사용자의 이미지

로긴해서 적으려니 KLDP로그인이 안되네요? 제 계정은 aero 인데 없는계정이라고 나옴

#!/usr/bin/env perl
use strict;
use warnings;
 
my (@sum, @max);
 
while (my $line = <DATA>) {
    my $i = 0;
    foreach my $item ( split /\s+/, $line ) {
        $sum[$i] = 0 unless defined $sum[$i];
        $max[$i] = 0 unless defined $max[$i];
        if (!$item) {
            $sum[$i]++;
            $max[$i] = $sum[$i] > $max[$i] ? $sum[$i] : $max[$i];
        }
        else {
            $sum[$i] = 0;
        }
        $i++;
    }
}
print "@max\n";
 
__DATA__
1 1 2 0 0 1 0 1
1 1 2 0 0 1 1 0
2 1 2 0 1 2 0 1
1 1 0 1 0 1 0 1

결과

0 0 1 3 2 0 2 1

codepad 링크

http://codepad.org/AsThIyiJ

momo7의 이미지

감사합니다

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.