'다차원배열'에 해당되는 글 2건

  1. 2010.06.26 다차원배열의 구성
  2. 2010.06.25 array_merge()
WebApp/PHP2010. 6. 26. 02:15
데이터베이스를 통해 자료를 사용하다보면, 어떠한 방식으로 자료를 배열에 저장해야 좋을까 고민하게 된다.
데이터베이스를 다루는 프로그램의 진행 구조를 살펴보면, 이러한 고민에 부딪치는 까닭을 알 수 있다.

프로그램은 사용자의 요구에 따라(Input) 데이터베이스에 있는 정보를 꺼내어 배열에 저장하고(Process)
그 값을 화면 구성에 알맞게 적절하게 뿌리도록 프로그램을 작성한다.(Output)

우리는 처리Process 절차 - 데이터베이스에 있는 정보를 변수에 저장하는 단계를 위해서 이를 고민하고 있는 것이다. 그렇다면, 배열 구성 방식에 관한 문제는 어떠한 방법이 출력Output 단계에서 효율적인지만을 확인하면 되는 것이다.

게시판 프로그램을 작성한다는 가정 하에 이 문제를 풀어보도록 하자.
현재 나타나고 있는 게시판은 다음과 같다.
 제목 내용  작성자 
 php입문 php는 <?php로 시작해서 ?>로 끝납니다. php.net
 html입문 html은 <html>로 시작해서 </html>로 끝납니다. w3c.org

이 게시판의 HTML코드는 다음과 같다.
<table>
<tr>
<th>제목</th>
<th>내용</th>
<th>작성자</th>
</tr>
<tr>
<td>php입문</td>
<td>php는 &lt;?php로 시작해서 ?&gt;로 끝납니다.</td>
<td>php.net</td>
</tr>
<tr>
<td>html입문</td>
<td>html은 &lt;html&gt;로 시작해서 &lt;/html&gt;로 끝납니다.</td>
<td>w3c.org</td>
</tr>
</table>
또한 SQL 테이블 구조는 다음과 같다 .
table : `board`
columns: `subject`, `description`, `author`

다음은 위의 내용을 담기 위한 제 1의 배열 방법이다. 위의 표에서 가로축에 해당하는 것을 1차 배열로 놓는 경우이다.
$board => Array
(
[subject] => Array
(
[0] => php입문
[1] => html입문
)
[description] => Array
(
[0] => php는 <?php로 시작해서 ?>로 끝납니다.
[1] => html은 <html>로 시작해서 </html>로 끝납니다.
)
[author] => Array
(
[0] => php.net
[1] => w3c.org
)
)

제 2의 방법은 다음과 같다. 위의 표에서 세로축에 해당되는 것을 1차 배열로 놓는 경우이다.
$board => Array
(
[0] => Array
(
[subject] => php입문
[description] => php는 <?php로 시작해서 ?>로 끝납니다.
[author] => php.net
)
[1] => Array
(
[subject] => html입문
[description] => phtml은 <html>로 시작해서 </html>로 끝납니다.
[author] => w3c.org
)
)

어느것이 효율적인 저장방법일까? 다음의 예제들을 통해서 확인해보자.

첫째는 위의 배열들을 게시물에 뿌리는 방법이다.
제1의 방법을 통한 예제를 먼저 보겠다.
echo "<table>";
echo "<tr>";
echo "<th>제목</th>";
echo "<th>내용</th>";
echo "<th>작성자</th>";
echo "</tr>";
$counter = count($board[subject]);
for($i=0; $i<$counter; $i++) {
echo "<tr>";
echo "<td>".$board[subject][$i]."</td>";
echo "<td>".$board[description][$i]."</td>";
echo "<td>".$board[author][$i]."</td>";
echo "</tr>";
}
echo "</table>";
코드를 보면, 일단 for 반복문의 반복 횟수를 결정하는 문제부터 막힌다.
위에서 제시한 표만 처리하는 코드이기 때문에 여기서는 카운터 횟수를 쉽게 결정했지만,
좀더 유연한 코드를 작성하고자 한다면 처리하기가 매우 어려울 것이다.
한 가지 예를 들자면 다음처럼 몇몇 값이 비어있는 채로 넘어오는 경우이다.
$board => Array
(
[subject] => Array
(
[1] => html입문
)
[description] => Array
(
[0] => php는 <?php로 시작해서 ?>로 끝납니다.
)
[author] => Array
(
[0] => php.net
[1] => w3c.org
)
)
위와 같은 경우는 우리가 원하는 결과를 얻지 못하게 되는 것이다.

그렇다면, 제2의 방법은 어떠할까?
echo "<table>";
echo "<tr>";
echo "<th>제목</th>";
echo "<th>내용</th>";
echo "<th>작성자</th>";
echo "</tr>";
foreach($board as $value) {
echo "<tr>";
echo "<td>".$value[subject]."</td>";
echo "<td>".$value[description]."</td>";
echo "<td>".$value[author]."</td>";
echo "</tr>";
}
echo "</table>";
눈에 띄게 차이가 나지는 않지만, 위의 코드보다 더 간단하다.
반복문의 반복 횟수를 결정하기 위해 고민할 필요도 없이 foreach문만으로도 작성이 가능하다.
또한 제1의 방법과 달리 아래처럼 몇몇 요소가 빠지더라도 반복 횟수에는 문제가 없다.
$board => Array
(
[0] => Array
(
[description] => php는 <?php로 시작해서 ?>로 끝납니다.
[author] => php.net
)
[1] => Array
(
[subject] => html입문
[author] => w3c.org
)
)
얻을 수 있는 것은 이것 뿐만이 아니다. 안의 변수구성도 간단해졌다.
변수에 $i같은 군더더기 요소가 사라짐으로써, 바이트를 좀 더 줄였다.
PHP와 같은 스크립트 프로그램의 경우에는 파일의 용량이 줄어들수록 처리 엔진의 부하가 줄어들기 때문에 더 효과적이다.

둘째는 데이터베이스에서 자료를 꺼내는 것이 아니라 저장하는 경우이다.
제1의 방법을 보자.(execute_query() 함수에 관련해서는 본 블로그에서 검색해보기 바란다.)
$counter = count($board[subject]);
for($i=0; $i<$counter; $i++) {
unset($keys, $values);
foreach($board as $key => $value) {
if($keys==NULL) {
$keys = "`".$key."`";
$values = "'".$value[$i]."'";
} else {
$keys .= ",`".$key."`";
$values .= ",'".$value[$i]."'";
}
}
$query = "INSERT INTO `board` ($keys) VALUES ($values)";
$result = execute_query($query);
}
앞서 말했던 반복 횟수에 대한 비효율이 계속 나타난다.
또 한 가지 주목해야 할 사항은 NULL값에 대한 비효율문제이다.
만약 배열의 값이 다음과 같이 구성이 되어 있다고 하자.
$board => Array
(
[subject] => Array
(
[1] => html입문
)
[description] => Array
(
[0] => php는 <?php로 시작해서 ?>로 끝납니다.
)
[author] => Array
(
[0] => php.net
[1] => w3c.org
)
)
위의 코드와 같은 경우는 다음과 같은 쿼리문을 만들어낼 것이다.
INSERT INTO `board` (`subject`, `description`, `author`) VALUES ('', 'php는 <?php로 시작해서 ?>로 끝납니다.', 'php.net')
INSERT INTO `board` (`subject`, `description`, `author`) VALUES ('html입문', '', 'w3c.org')
이와 같은 쿼리문은 쓸데 없이 NULL값을 데이터베이스에 입력하게 된다.
이에 대한 유일한 대안인 제2의 방법을 살펴보자.
foreach($board as $item) {
unset($keys, $values);
foreach($item as $key => $value) {
if($keys==NULL) {
$keys = "`".$key."`";
$values = "'".$value."'";
} else {
$keys .= ",`".$key."`";
$values .= ",'".$value."'";
}
}
$query = "INSERT INTO `board` ($keys) VALUES ($values)";
$result = execute_query($query);
}
코드는 $i가 빠졌다거나 하는 소소한 차이일 뿐 거의 달라진 것이 없다.
하지만 한 가지 분명한 것은 NULL값 입력과 같은 비효율적 현상은 나타나지 않는다.
만약 배열의 구성이 다음과 같다고 하자.
$board => Array
(
[0] => Array
(
[description] => php는 <?php로 시작해서 ?>로 끝납니다.
[author] => php.net
)
[1] => Array
(
[subject] => html입문
[author] => w3c.org
)
)
이러한 경우 이 코드는 다음과 같은 쿼리문을 만들어 낸다.
INSERT INTO `board` (`description`, `author`) VALUES ('php는 <?php로 시작해서 ?>로 끝납니다.','php.net')
INSERT INTO `board` (`subject`, `author`) VALUES ('html입문','w3c.org')
군더더기 없이 깔끔한 모습이다.

지금까지 더 효율적인 다차원 배열 구성을 찾기 위해 몇 가지 예를 살펴보았다.
for 루프문의 구성이나 그것을 통한 출력물에 있어서, $변수[항목][숫자]의 형태보다 $변수[숫자][항목] 형태의 구성이 더 효율적임을 입증하였다.
앞으로 이러한 배열 형태를 기반으로 하는 많은 알고리즘들을 생겨났으면 한다.
Posted by 마이클
WebApp/PHP2010. 6. 25. 16:08
PHP에는 배열을 합칠 수 있는 array_merge()함수가 있다.
인자는 두 개의 배열로써 호출할 때는 다음과 같이 호출한다.
$array = array_merge($array1, $array2);

$array1에 $array2에 내용을 끼워 넣어 결과 값을 리턴한다.
그렇기 때문에, 다음 코드를 실행하게 되면
$array[0] = array(1, 2, 3);
$array[1] = array("a", "b", "c");
for($i=0; $i<count($array); $i++) {
$return = array_merge($array[$i], $return);
}
print_r($return);

$array[1]에 $array[0]을 끼워넣는 것이 되므로, 다음과 같이 아래 위가 뒤집힌 값이 나타난다.
Array
(
[0] => a
[1] => b
[2] => c
[3] => 1
[4] => 2
[5] => 3
)
이를 바로잡기 위해서는 함수 인자들의 위치를 신경 써주어야 하겠다.

또한, array_merge함수의 다른 한 가지 특징은 해당 숫자 배열이 존재하는 경우 그 배열명을 피해서 저장한다는 점에 있다.
눈치가 빠른 사람들은 위의 예제에서 눈치 챘겠지만, 위의 예제에서 사용한 배열 두 개의 값은 다음과 같다.
Array
(
[0] => 1
[1] => 2
[2] => 3
)
Array
{
[0] => a
[1] => b
[2] => c
)
이렇게 중복되는 배열명이 존재하는 경우 그것을 자동적으로 피해서 저장하는 것이다.

하지만 문자 배열의 경우에는 신경을 쓸 필요가 있다. 다음 예제를 살펴보자.
$array1 = array("id" => "identification");
$array2 = array("id" => "i.d.");
$result = array_merge($array1, $array2);
print_r($result);
이것을 실행하게 되면 다음과 같은 결과 값이 나타난다.
Array
(
[id] => Array
(
[0] => identification
[1] => i.d.
)
)
배열이 아니었던 배열명 id의 값을 배열로 저장하고 있는 것이다.

array_merge는 다차원배열도 물론 지원한다.
$array1 = array("member" => array("id"=>"identification"));
$array2 = array("member" => array("pw" => "password"));
$result = array_merge($array1, $array2);
print_r($result);
위의 코드를 실행시키면 , 다음과 같은 결과 값이 나타난다.
Array
(
[member] => Array
(
[id] => identification
[pw] => password
)
)

하지만 1차 배열명이 숫자인 경우에는 문제가 좀 달라진다.
$array1 = array(array("id"=>"identification"));
$array2 = array(array("pw" => "password"));
$result = array_merge($array1, $array2);
print_r($result);
혹시 다음과 같은 결과 값을 예상하고 있지는 않은가?
Array
(
[0] => Array
(
[id] => identification
[pw] => password
)
)
하지만 array_merge()함수는 이처럼 작동하지 않는다.
해당 배열명이 숫자 그리고 그 배열명에 해당하는 값이 NULL이 아닌경우,
NULL값인 숫자 배열명이 나타날때까지 찾아서 그곳에 값을 입력한다.
위의 코드를 통해 말하자면, 현재 [0]은 NULL이 아니므로, 다음 숫자 배열명인 [1]에 값을 저장하게 되는 것이다.
그러므로 위 코드의 결과 값은 다음과 같이 나타난다.
Array
(
[0] => Array
(
[id] = identification
)
[1] => Array
(
[pw] = password
)
)

문자 배열이나 숫자 배열이나 일관된 방법으로 배열을 저장하는 함수를 개발 중이므로,
개발이 완료되면 공개하도록 하겠다.

'WebApp > PHP' 카테고리의 다른 글

foreach 배열 반복  (0) 2010.08.12
다차원배열의 구성  (0) 2010.06.26
Form과 Input 태그로 배열 넘기기  (0) 2010.06.24
파일 경로 숨긴 채로 전송 및 다운로드하기  (0) 2010.06.07
파일 읽기 함수  (0) 2010.05.30
Posted by 마이클