배열(array)

배열(Array)은 일반 변수(scalar)들이 순서대로 늘어서 있는 변수들의 집합체이며, 일반 변수가 숫자와 문자열을 같이 수용하는 것처럼, 각 요소는 숫자일 수도, 문자열일 수도 있다고 했습니다. 그래서,
@arr = ( 8, 7, "Not a number" 6, "But a string" );
print "@arr\n";   # ""로 출력하면 각요소 사이에
                  # 공백이 들어간다고 했습니다.
가 성립이 된다고 했습니다. 또 배열의 참조 번호(index No.)는 0에서부터 시작하고, 마지막 참조변수는 $#arrayName으로 알 수 있다고 했고요.

배열의 일부는 그 자체로서 독립적인 배열의 역할을 합니다. 배열의 일부는 @array[시작참조번호..끝참조번호]로 나타냅니다.

# arrpart.pl

@arr = ( 3, 7, "Not number", 8, "String" );
@arr2 = @arr[1..3];   # 배열에 배열을 복사합니다.
$n = 4;
print "@arr[1..$n]\n";
print "@arr2\n";
print "$arr2[1]\n";
위에서 @arr[1..3]은 배열 @arr의 참조번호 1에서 3번 까지의 요소들의 배열이라는 의미입니다. 배열을 복사하기 위하여 Perl에서는 C, C++처럼 복잡한 단계를 거치지 않습니다. 위에서처럼 = (할당 연산자)를 이용하여 할당하기만 하면 새로운 배열이 초기화 되어 각 요소의 값들이 복사됩니다. 이런 일을 하면서도 C, C++처럼 메모리에 대하여 크게 걱정하지 않아도 되니 정말 뱃속이 편하군요.
결과적으로 @arr2는 ( 7, "Not number", 8 )이 됩니다. 원래의 배열 @arr에는 아무런 변화가 없음을 그 다음줄에서 볼 수 있습니다.

위에서는 배열의 크기가 작아졌지만, 배열의 크기가 커질 때는 어떻게 해야 할까요 ?

@arr = ( 2, 5, 3, 87, 2 );
# 그리고
$aaa = 4;
$bbb = 23;
$aaa, $bbb를 배열 @arr의 뒷 쪽에 붙여 새로운 큰 배열을 만든다고 하지요. 해결은 매우 간단합니다.
@arr2 = ( @arr, $aaa, $bbb );
새로운 배열 @arr2는 ( 2, 5, 3, 87, 2, 4, 23 )이 됩니다. 또,
@arr2 = ( "Fore", @arr, $aaa, $bbb, "aft", 2 );
@arr2 = ( "fore", @arr[2..4], $aaa, "aft" );
@arr2 = ( @arr[0-2], $aaa, $bbb );
등도 가능합니다.
배열로부터 각요소의 데이타를 끌어내는 방법들에 대해 살펴 보겠습니다.
@personal = ( "Jongpil", 32, "Seoul, Korea", "male" );
일 경우,
$name = $personal[0];  # 매우 고전적인 방법이군요.
$age  = $personal[1];
$home = $personal[2];
$sex  = $personal[3];

# 더욱 편리한 방법은 -
( $name, $age, $home, $sex )  = @personal;
     # C, C++의 구조체(structure)와 비슷한 데가 있지요 ?
print "The name is $name.\n";

$firstData = shift( @personal ); # 첫번째 요소는 $firstData에
                                 # 할당된 후 사라집니다.
$lastData  = pop( @personal );   # 마지막 요소가 $lastData에
                                 # 할당된 후 사라집니다.
shift와 pop함수는 배열을 다루는 함수입니다. 아래의 예제를 한번 실행해 보세요.
# shiftpop.pl

@arr = ( 1, 2, 3, 4, 5, 6 );
$first = shift @arr;
print "$first @arr\n";
$second = shift @arr;
print "$first $second @arr\n";
$last  = pop @arr;
print "$first $second @arr $last\n";
또,
# boom.pl

@arr = ( 1, 2, 3, 4, 5, 6 );

while( $elem = pop( @arr ) )  # pop을 shift로 바꾸어서도 해보세요.
  {  print "$elem\n";  }

print "BOOM ! @arr\n";
shift와 pop은 각각 배열의 앞과 뒤에서 하나의 요소를 끄집어 내는 함수임을 쉽게 알 수 있습니다.

어떤 배열의 뒷부분을 용감하게 잘라내려면 그 배열의 참조번호를 줄이는 것 만으로 가능합니다. 그러나 이 방법은 잘려나간 부분의 값을 알 수 없으므로 사용에 주의를 요구합니다. 물론 배열의 크기를 늘리는데도 이 방법이 통합니다. 단지 아무런 값이 없는 요소의 자리만이 마련되지요. $#arrayName += 3이라고하면 배열의 크기는 3자리 만큼 늘어납니다.

@arr = ( 1, 2, 3, 4, 5, 6 ); #현재 $#arr는 5 입니다. 아시죠 ?
$#arr = 3;  # $arr[4], $arr[5]는 없어집니다.
print $arr[4], "\n";  # "\n"만을 출력합니다.
그러나 다시,
$arr[4] = 9;
print "@arr\n";
# 그리고 또,
$arr[6] = 100;   # $arr[5]는 어떻게 하고 . . . ?
print "@arr\n";  # $arr[5]는 자리만 있고 값은 할당되지 않습니다.
이렇게 하면 크기도 늘어 납니다. Perl의 배열은 고무줄처럼 늘어납니다.
재미있는 예재가 하나 있습니다. 여러분도 한 번 실행해 보세요. 저하고 같은 결과가 나오겠죠 ? 이 테스트는 도스용 4.x로 해 본겁니다.
# cutpaste.pl

@a = ( 1,2,3,4,5,6 );

print "@a\n";

$#a -= 2;
print "@a\n";

$#a += 2;
print "@a\n";  # 다시 보이는 5와 6 !

$#a -= 2;
print "@a\n";

$a[5] = 7;
print "@a\n";  # 사라진 5 !
위에서 pop이란 함수를 보셨습니다. 당연히 push가 있겠지요.
@arr = ( 1, 2, 3, 4, 5, 6 );
$first = shift( @arr );
push( @arr, "last" );
push( @arr, "again", "more" );
@arr3 = ( "not", "again" );
push( @arr, @arr3 );
push( @arr, ( "Oh,", "stop", "it !" ) );
print "$first @arr\n";
push는 맨 마지막에 push된 값을 리턴합니다. @arr3 = ( "not", "again" )를 @arr에 push할 경우 리턴되는 값은 "again"이지요.
print( "@array" )의 효과에 대해서 아실겁니다. 사실 "@array"는 전체적으로 볼 때 배열이 아니라 일반 변수(scalar)입니다. 그저 문자열일 뿐이며 단지 배열이 실제 내용으로 치환되는 '작용'이 있을 뿐이지요. 그래서,
$arr = "@arr";
print $arr, "\n";  # print "@arr\n"과 같습니다.
라고 해도 내용은 같습니다. 그러나 주의 하십시오.
$arr = @arr;
print $arr, "\n";
에서는 $arr에 ( $#arr + 1 )이 할당됩니다.

변수 이름

$arr = @arr;, $arr = "@arr" 조금 이상해 보입니까 ? 그러나 분명히 $와 @의 차이가 있습니다. $arr와 $arr[1]에는 [] 참조연산자가 차이를 보여주고요. 헷갈리는것은 우리 사람들의 눈이지 Perl번역기는 아닙니다. 그래서 $arr, @arr, %arr모두를 한 프로그램 안에서 사용할 수 있지요. 그런 변수 이름을 사용하느냐 마느냐는 프로그래머의 선택입니다. 통일성을 위해서 같은 이름을 사용할 수도, 혼동을 피하기 위해 다른 이름을 사용할 수도 있습니다. 우리 눈의 착각을 정리하기 위해서도 예제를 직접 만들어서 실행해 보는것은 필수입니다.

몇가지 예를 또 보겠습니다.
( $a, $b ) = ( $x, $y );  # $a = $x; $b =$y 와 같습니다.
          # ( , , , .... )도 이름만 없을 뿐 역시 배열입니다.
          # @forearray = @aftarray와는 모양만 다를 뿐 내용은
          # 같습니다.
( $a, $b ) = ( $w, $x, $y, $z )[1..2]; # 위와 같습니다.
( $a, @dish ) = @food;    # $a = $food[0];
                          # @dish = @food[1..$#food];
( @dish, $rest ) = @food; # @dish = @food;  # 주의 !!
                          # $rest는 아무것도 할당 안됨.
이제 join이라는 함수에 대해 알아 보겠습니다.
$arr = "@arr"가 배열의 요소간에 공백을 넣어서 전체를 연결하는 역할을 해 주는데 비해 join은 공백이 아닌 다른 문자(들)를 이용하여 배열의 각 요소를 연결할 수 있습니다.
$str  = join( ':', @arr );
print( "$str\n" );
$str  = join( ':::', @arr );
print( "$str\n" );
$str  = join( ' ', @arr );
print( "$str\n" );
join함수는 여러분의 데이타를 묶어서 파일에 저장하기 전에 후일 다시 검색하여 split으로 다시 풀어 헤치기 위한 준비를 하는데도 적합합니다.
다음의 예제는 학생들의 ID, 이름, 학년을 'studile'이라는 파일에 저장하는 간단한 예제입니다. hash와 배열이 어떻게 사용되는지 잘 살펴 보십시오.
# savestud.pl

$stufile = 'stufile';

$students{ 123 } = "Jongpil";   # students는 hash 입니다.
$students{ 246 } = "Inhyon";    # 따라서 각 요소를 지정하기 위하여
$students{ 357 } = "Jungkwang"; # {}를 사용합니다.
$students{ 212 } = "Kwanghoon"; # 숫자가 들어간다고 해서 배열로
                                # 착각해서는 안되어요.
$studyear{ 123 } = 2;
$studyear{ 246 } = 1;
$studyear{ 357 } = 3;
$studyear{ 212 } = 2;
  # 이제 두 개의 hash %students와 %studyear가 만들어졌습니다.

open( Hstufile, ">$stufile" ) || die "Can\'t open $stufile";
  # 파일을 쓰기 모드(>)로 열었습니다.
foreach ( keys %students )  # keys 함수는 hash의 key들만을 모아서
{                           # 배열로 만들어 return한다고 했습니다.
  $stud[0] = $_;      # $_ 기억하시죠 ?
  $stud[1] = $students{$_};
  $stud[2] = $studyear{$_};

  $string = join( ':', @stud );  # : 부호로 join합니다.
  $string .= "\n";               # ID와 학년, 그리고 사람 이름에
                                 # 들어갈리 없는 부호니까요.
  print Hstufile $string;  # 핸들을 통해서 파일에 프린트합니다.
}

close Hstufile;  # 꼭, 닫읍시다.
split 함수를 기억하십니까 ? join함수의 역개념이지요. 지금 그것을 다시 설명하면 제가 여러분을 무시하는것이 되겠지요 ? 그러나 join에 짝이 없어서 서운하니까 한마디만 할께요.
split함수는 어떤 패턴을 이용하여 문자열을 배열로 나누어 저장합니다. 궁금하시면 저의 Perl 이야기-3의 맨 뒷부분을 참조하세요.

Perl에 관한 문서들을 보면 자주 나오는 이야기가 있습니다. "방법은 한 가지 만은 아니다"는 말입니다. 여러가지 방법을 고려해서 문제를 풀어 나가십시오. 어떤 문제던지...


이전 | 목록 | 다음
Comments