[perl] 일정 갯수, 같은 열끼리 합한 값을 추출할때

momo7의 이미지

1 1 1 2 3 2 1 2 1 1 2
1 1 1 2 3 2 1 2 1 1 2
1 1 1 2 3 2 1 2 1 1 2
1 1 1 2 3 2 1 2 1 1 2
1 1 1 2 3 2 1 2 1 1 2
1 1 1 2 3 2 1 2 1 1 2

위와 같은 파일 샘플에서 같은 열끼리 합산을 하는데,

첫번째줄부터 세번째 줄까지의 합을 출력하고,

그 다음에는 두번째 줄에서 네번째 줄까지 합하여 출력하고

그 다음에는 세번째 줄에서 다섯번째 줄까지 합하여 출력하고자 합니다.

인터넷에서 코드를 참조하여 아래와 같이 만들었는데

반복수행전까지는 실행이 되나 반복수행(1번째 줄에서 3번째, 2번째에서 4번째,...)은 되질 않습니다

혹시 힌트주실분 있으신가요?

use 5.010;
use Getopt::Long;
my ($file, $howmany, $j);
my (@arr, %arr, $row);
my $result = GetOptions (
"l=s" => \$howmany,
);

for ($j=1; $j<5; $j++){ # <---- 이 문장을 넣기 전까지는 잘 작동합니다.

while(<>){
if ($. >= $j and $. < $j + $howmany) {
@arr=split(/\s*$+/, $_);
for (my $i=0; $i<=$#arr; $i++) {
$arr{$i}+=$arr[$i];
}
$row++;
}
}

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

}

Tony의 이미지

원하시는게 뭔지 조금 헤깔리기는 하지만...
아래의 코드처럼 만들기를 원하셨던게 아닐까 추측해봤습니다.

원 코드에서 while(<>) 이런식으로 쓸 경우 인풋파일을 순서대로 읽어나가기만 하기때문에
5번 반복을 원한다면 매번 파일을 새로 오픈해야됩니다.
다만 이런경우 매번 파일을 새로 오픈해서 처음부터 다시 읽기때문에 처리해야할 양이 많다면 속도가 느릴 수 있을 것 같습니다.
속도가 문제라면 로직 자체를 새로 고민하시면 될것같습니다.

use 5.010;
use Getopt::Long;
my ($file, $howmany, $j);
my $result = GetOptions (
    "f=s" => \$file,
    "l=s" => \$howmany,
);
 
 
for ($j=1; $j<5; $j++){ # <---- 이 문장을 넣기 전까지는 잘 작동합니다.
 
    my (@arr, %arr, $row);
    open my $fd, '<', $file;
    while(<$fd>){
        if ($. >= $j and $. < $j + $howmany) {
            @arr=split(/\s*$+/, $_);
            for (my $i=0; $i<=$#arr; $i++) {
                $arr{$i}+=$arr[$i];
            }
        $row++;
        }
    }
    close($fd);
 
    print (($arr{$_})," ") for (sort {$a <=> $b} keys (%arr));
    print "\n";
 
}

$ ./test.pl -f ./data.txt -l 3
3 3 3 6 9 6 3 6 3 3 6
3 3 3 6 9 6 3 6 3 3 6
3 3 3 6 9 6 3 6 3 3 6
3 3 3 6 9 6 3 6 3 3 6

저처럼 c스타일의 펄 코드를 구사하시는분의 글이라 반가운마음에 얼른 보자마자 리플을 달았습니다 ㅎㅎ
자세한 가이드를 원하신다면 irc freenode #perl-kr 룸으로 오세요~

amorette의 이미지

힌트 대신 작성해 보았습니다.

#!/usr/bin/env perl
use 5.010;
use List::Util qw(reduce);
use List::MoreUtils qw(pairwise);
 
my $size = 3;
my @buf;
 
use Getopt::Long;
GetOptions "line=s" => \$size;
 
merge();
 
sub merge {
    while (<>) {
        chomp;
        push  @buf, [ split ];
        shift @buf if @buf > $size;
        if (@buf == $size) {
            my $sum = sum_colwise( @buf );
            say "@$sum";
        }
    }
}
 
sub sum_colwise {
    reduce {
        $a = [ pairwise { $a + $b } @$a, @$b ]; 
    } @_;
}
momo7의 이미지

Tony님, amorette님 두분 모두 감사드립니다. 우문현답이였습니다.

제가 처리해야할 파일이 개당 1기가 짜리여서 무척이나 고민하던 것이였는데..

덕분에 쉽게 처리되었습니다.

펄을 배우기 시작한지 얼마 되지 않아서 아직 규칙도 헷갈리고 그렇습니다.

제가 테스트 해본결과 두개 모두 잘 되었으나 Tony님께서 해주신 부분에서(원래 이해를 잘못해 작성한 것인지 몰라도)

split(/\s*$+/, $_) *를 이용하여 처리하면 두자리 이상이 되면 이상하게 각 자리 숫자로 분리되어 연산하는 현상을 발견하였습니다(제가 원래 알기론 *를 사용해야 하는걸로 알았는데, 누가 이거 설명해주실 분 있으신가요?)

그래서 split(/\s+$+/, $_) 이와같이 변경하여 테스트 하였더니

잘 수행되었습니다.

혹시 필요하신분은 아래와 같은 소스를 사용하시거나, amorette님이

작성해주신 소스를 사용하시기 바랍니다.

use 5.010;
use Getopt::Long;
my ($file, $howmany, $j);
my $result = GetOptions (
"f=s" => \$file,
"l=s" => \$howmany,
);


for ($j=1; $j<5; $j++){

my (@arr, %arr, $row);
open my $fd, '<', $file;
while(<$fd>){
if ($. >= $j and $. < $j + $howmany) {
@arr=split(/\s+$+/, $_);
for (my $i=0; $i<=$#arr; $i++) {
$arr{$i}+=$arr[$i];
}
$row++;
}
}
close($fd);

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

}

Tony의 이미지

split을 처음 코드에선
\s*$+
으로 하셨던데요.

뒤에 붙은 $+는 의미가 없는거라 빼셔도 될것같습니다. 그러면 남는 코드가
\s*
이렇게 되는데요 \s 는 whitespace를 의미하니까 whitespace가 0개 이상일경우 split 한다라고 해석됩니다.

0개 이상이다보니 whitespace가 없어도 split을 하게되서 두자리 이상일 경우에는 하나씩 분리가 되었습니다.

결론적으로 whitespace를 기준으로 split을 하려면

\s+

를 쓰면 됩니다.

결국 위의 코드는
@arr=split(/\s+/, $_);

이렇게 쓸 수 있습니다.

좀더 줄이면
@arr = split /\s+/, $_;

$_는 생략할 수 있으니까...

@arr = split /\s+/;

이렇게 줄일수 있겠네요.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.