문제: 상황에 맞지 않는 정렬 함수 사용으로 인한 오류
<?php
// 다양한 정렬 함수 비교
// 1. 값 기준 정렬 (키 유지 안함)
$numbers = [3, 1, 4, 1, 5, 9, 2, 6];
$sorted_numbers = $numbers;
echo "원본 배열:\n";
print_r($numbers);
// sort() - 오름차순, 키 재배열
sort($sorted_numbers);
echo "sort() 결과:\n";
print_r($sorted_numbers);
// rsort() - 내림차순, 키 재배열
$rsorted_numbers = $numbers;
rsort($rsorted_numbers);
echo "rsort() 결과:\n";
print_r($rsorted_numbers);
// 2. 값 기준 정렬 (키 유지)
$fruits = [
'b' => 'banana',
'a' => 'apple',
'c' => 'cherry',
'd' => 'date'
];
echo "\n연관 배열 원본:\n";
print_r($fruits);
// asort() - 값 기준 오름차순, 키 유지
$asorted_fruits = $fruits;
asort($asorted_fruits);
echo "asort() 결과 (값 기준, 키 유지):\n";
print_r($asorted_fruits);
// arsort() - 값 기준 내림차순, 키 유지
$arsorted_fruits = $fruits;
arsort($arsorted_fruits);
echo "arsort() 결과 (값 기준 내림차순, 키 유지):\n";
print_r($arsorted_fruits);
// 3. 키 기준 정렬
$ksorted_fruits = $fruits;
ksort($ksorted_fruits);
echo "ksort() 결과 (키 기준 오름차순):\n";
print_r($ksorted_fruits);
$krsorted_fruits = $fruits;
krsort($krsorted_fruits);
echo "krsort() 결과 (키 기준 내림차순):\n";
print_r($krsorted_fruits);
?>
문제: 복잡한 정렬 조건을 기본 함수로 처리할 수 없음
<?php
// 사용자 정의 정렬 예제
$products = [
['name' => 'iPhone', 'price' => 1200000, 'rating' => 4.5, 'category' => 'phone'],
['name' => 'Galaxy', 'price' => 1000000, 'rating' => 4.3, 'category' => 'phone'],
['name' => 'iPad', 'price' => 800000, 'rating' => 4.7, 'category' => 'tablet'],
['name' => 'MacBook', 'price' => 2000000, 'rating' => 4.8, 'category' => 'laptop'],
['name' => 'Surface', 'price' => 1500000, 'rating' => 4.2, 'category' => 'laptop']
];
echo "원본 상품 목록:\n";
foreach ($products as $product) {
echo "{$product['name']} - {$product['price']}원 - 평점: {$product['rating']}\n";
}
// 1. 가격 기준 오름차순 정렬
$price_sorted = $products;
usort($price_sorted, function($a, $b) {
return $a['price'] <=> $b['price'];
});
echo "\n가격 기준 오름차순:\n";
foreach ($price_sorted as $product) {
echo "{$product['name']} - {$product['price']}원\n";
}
// 2. 평점 기준 내림차순 정렬
$rating_sorted = $products;
usort($rating_sorted, function($a, $b) {
return $b['rating'] <=> $a['rating'];
});
echo "\n평점 기준 내림차순:\n";
foreach ($rating_sorted as $product) {
echo "{$product['name']} - 평점: {$product['rating']}\n";
}
// 3. 다중 조건 정렬 (카테고리 -> 가격)
$multi_sorted = $products;
usort($multi_sorted, function($a, $b) {
// 먼저 카테고리로 정렬
$category_compare = strcmp($a['category'], $b['category']);
if ($category_compare !== 0) {
return $category_compare;
}
// 카테고리가 같으면 가격으로 정렬
return $a['price'] <=> $b['price'];
});
echo "\n카테고리 -> 가격 순 정렬:\n";
foreach ($multi_sorted as $product) {
echo "{$product['category']} - {$product['name']} - {$product['price']}원\n";
}
?>
문제: 복잡한 다차원 배열에서 특정 필드로 정렬하기 어려움
<?php
// 다차원 배열 정렬 클래스
class ArraySorter {
/**
* 다차원 배열을 특정 키로 정렬
*/
public static function sortByKey($array, $key, $direction = 'asc') {
usort($array, function($a, $b) use ($key, $direction) {
$valueA = self::getNestedValue($a, $key);
$valueB = self::getNestedValue($b, $key);
$result = $valueA <=> $valueB;
return $direction === 'desc' ? -$result : $result;
});
return $array;
}
/**
* 중첩된 키로 값 가져오기 (예: 'user.profile.age')
*/
private static function getNestedValue($array, $key) {
$keys = explode('.', $key);
$value = $array;
foreach ($keys as $k) {
if (is_array($value) && isset($value[$k])) {
$value = $value[$k];
} else {
return null;
}
}
return $value;
}
/**
* 다중 조건 정렬
*/
public static function sortByMultiple($array, $criteria) {
usort($array, function($a, $b) use ($criteria) {
foreach ($criteria as $criterion) {
$key = $criterion['key'];
$direction = $criterion['direction'] ?? 'asc';
$valueA = self::getNestedValue($a, $key);
$valueB = self::getNestedValue($b, $key);
$result = $valueA <=> $valueB;
if ($result !== 0) {
return $direction === 'desc' ? -$result : $result;
}
}
return 0;
});
return $array;
}
}
// 테스트 데이터
$users = [
[
'id' => 1,
'name' => '김철수',
'profile' => [
'age' => 30,
'city' => '서울',
'score' => 85
],
'created_at' => '2023-01-15'
],
[
'id' => 2,
'name' => '이영희',
'profile' => [
'age' => 25,
'city' => '부산',
'score' => 92
],
'created_at' => '2023-02-20'
],
[
'id' => 3,
'name' => '박민수',
'profile' => [
'age' => 35,
'city' => '서울',
'score' => 78
],
'created_at' => '2023-01-10'
]
];
echo "원본 데이터:\n";
foreach ($users as $user) {
echo "{$user['name']} - 나이: {$user['profile']['age']} - 점수: {$user['profile']['score']}\n";
}
// 나이 기준 정렬
$age_sorted = ArraySorter::sortByKey($users, 'profile.age');
echo "\n나이 기준 오름차순:\n";
foreach ($age_sorted as $user) {
echo "{$user['name']} - 나이: {$user['profile']['age']}\n";
}
// 점수 기준 내림차순 정렬
$score_sorted = ArraySorter::sortByKey($users, 'profile.score', 'desc');
echo "\n점수 기준 내림차순:\n";
foreach ($score_sorted as $user) {
echo "{$user['name']} - 점수: {$user['profile']['score']}\n";
}
// 다중 조건 정렬 (도시 -> 나이)
$multi_sorted = ArraySorter::sortByMultiple($users, [
['key' => 'profile.city', 'direction' => 'asc'],
['key' => 'profile.age', 'direction' => 'asc']
]);
echo "\n도시 -> 나이 순 정렬:\n";
foreach ($multi_sorted as $user) {
echo "{$user['profile']['city']} - {$user['name']} - 나이: {$user['profile']['age']}\n";
}
?>
문제: 숫자가 포함된 문자열이나 특수한 형태의 데이터 정렬
<?php
// 자연 정렬 및 특수 정렬 예제
// 1. 자연 정렬 (숫자 포함 문자열)
$files = [
'file1.txt',
'file10.txt',
'file2.txt',
'file20.txt',
'file3.txt'
];
echo "일반 정렬:\n";
$normal_sorted = $files;
sort($normal_sorted);
print_r($normal_sorted);
echo "자연 정렬:\n";
$natural_sorted = $files;
natsort($natural_sorted);
print_r($natural_sorted);
// 2. 버전 번호 정렬
$versions = ['1.10.0', '1.2.0', '1.9.0', '2.0.0', '1.2.1'];
echo "\n버전 번호 자연 정렬:\n";
$version_sorted = $versions;
usort($version_sorted, 'version_compare');
print_r($version_sorted);
// 3. 날짜 정렬
$dates = [
'2023-12-01',
'2023-01-15',
'2023-06-30',
'2023-03-20'
];
echo "\n날짜 정렬:\n";
$date_sorted = $dates;
usort($date_sorted, function($a, $b) {
return strtotime($a) <=> strtotime($b);
});
print_r($date_sorted);
// 4. 한글 정렬 (로케일 기반)
$korean_names = ['김철수', '이영희', '박민수', '최지영', '정다은'];
echo "\n한글 이름 정렬:\n";
$korean_sorted = $korean_names;
// 로케일 설정 (시스템에 따라 다를 수 있음)
if (setlocale(LC_COLLATE, 'ko_KR.UTF-8') !== false) {
usort($korean_sorted, function($a, $b) {
return strcoll($a, $b);
});
} else {
// 로케일 설정 실패 시 기본 정렬
sort($korean_sorted);
}
print_r($korean_sorted);
// 5. 사용자 정의 우선순위 정렬
$priorities = ['high', 'medium', 'low', 'urgent', 'normal'];
$priority_order = ['urgent' => 1, 'high' => 2, 'medium' => 3, 'normal' => 4, 'low' => 5];
echo "\n우선순위 정렬:\n";
$priority_sorted = $priorities;
usort($priority_sorted, function($a, $b) use ($priority_order) {
return $priority_order[$a] <=> $priority_order[$b];
});
print_r($priority_sorted);
?>
문제: 대용량 배열 정렬 시 성능 문제
<?php
// 성능 최적화된 정렬 클래스
class PerformanceSorter {
/**
* 대용량 배열을 위한 메모리 효율적 정렬
*/
public static function efficientSort($array, $callback = null) {
$start_memory = memory_get_usage();
$start_time = microtime(true);
if ($callback === null) {
sort($array);
} else {
usort($array, $callback);
}
$end_memory = memory_get_usage();
$end_time = microtime(true);
echo "정렬 완료:\n";
echo "- 실행 시간: " . round(($end_time - $start_time) * 1000, 2) . "ms\n";
echo "- 메모리 사용량: " . round(($end_memory - $start_memory) / 1024, 2) . "KB\n";
return $array;
}
/**
* 청크 단위로 나누어 정렬 (메모리 절약)
*/
public static function chunkSort($array, $chunk_size = 1000, $callback = null) {
$chunks = array_chunk($array, $chunk_size);
$sorted_chunks = [];
foreach ($chunks as $chunk) {
if ($callback === null) {
sort($chunk);
} else {
usort($chunk, $callback);
}
$sorted_chunks[] = $chunk;
}
// 정렬된 청크들을 병합
return self::mergeChunks($sorted_chunks, $callback);
}
/**
* 정렬된 청크들을 병합
*/
private static function mergeChunks($chunks, $callback = null) {
$result = [];
foreach ($chunks as $chunk) {
$result = self::mergeTwoArrays($result, $chunk, $callback);
}
return $result;
}
/**
* 두 정렬된 배열을 병합
*/
private static function mergeTwoArrays($arr1, $arr2, $callback = null) {
$result = [];
$i = $j = 0;
while ($i < count($arr1) && $j < count($arr2)) {
$compare = 0;
if ($callback === null) {
$compare = $arr1[$i] <=> $arr2[$j];
} else {
$compare = $callback($arr1[$i], $arr2[$j]);
}
if ($compare <= 0) {
$result[] = $arr1[$i++];
} else {
$result[] = $arr2[$j++];
}
}
// 남은 요소들 추가
while ($i < count($arr1)) {
$result[] = $arr1[$i++];
}
while ($j < count($arr2)) {
$result[] = $arr2[$j++];
}
return $result;
}
/**
* 인덱스 기반 정렬 (원본 배열 수정 없이)
*/
public static function indexSort($array, $callback = null) {
$indices = array_keys($array);
if ($callback === null) {
usort($indices, function($a, $b) use ($array) {
return $array[$a] <=> $array[$b];
});
} else {
usort($indices, function($a, $b) use ($array, $callback) {
return $callback($array[$a], $array[$b]);
});
}
return $indices;
}
}
// 대용량 데이터 테스트
echo "대용량 배열 정렬 테스트:\n";
// 10만개 랜덤 숫자 생성
$large_array = [];
for ($i = 0; $i < 100000; $i++) {
$large_array[] = rand(1, 1000000);
}
echo "배열 크기: " . count($large_array) . " 개\n";
// 일반 정렬
$test_array = $large_array;
echo "\n일반 정렬:\n";
PerformanceSorter::efficientSort($test_array);
// 청크 정렬
$test_array = $large_array;
echo "\n청크 정렬 (청크 크기: 5000):\n";
$chunk_sorted = PerformanceSorter::chunkSort($test_array, 5000);
// 인덱스 정렬
echo "\n인덱스 정렬:\n";
$small_test = array_slice($large_array, 0, 1000);
$indices = PerformanceSorter::indexSort($small_test);
echo "정렬된 인덱스 처음 10개: " . implode(', ', array_slice($indices, 0, 10)) . "\n";
?>
문제: 정렬 결과가 예상과 다르거나 오류 발생
<?php
// 정렬 디버깅 및 검증 클래스
class SortingDebugger {
/**
* 정렬 함수의 안정성 검증
*/
public static function validateSortFunction($callback, $test_cases = null) {
if ($test_cases === null) {
$test_cases = [
[1, 2],
[2, 1],
[1, 1],
['a', 'b'],
['b', 'a'],
[null, 1],
[1, null]
];
}
echo "정렬 함수 검증:\n";
foreach ($test_cases as $case) {
$result = $callback($case[0], $case[1]);
$status = self::validateComparisonResult($result);
echo "- {$case[0]} vs {$case[1]} = $result ($status)\n";
}
}
/**
* 비교 결과 검증
*/
private static function validateComparisonResult($result) {
if ($result < 0) return "첫 번째가 작음";
if ($result > 0) return "첫 번째가 큼";
return "같음";
}
/**
* 정렬 결과 검증
*/
public static function verifySortResult($array, $callback = null) {
$is_sorted = true;
$errors = [];
for ($i = 0; $i < count($array) - 1; $i++) {
$compare = 0;
if ($callback === null) {
$compare = $array[$i] <=> $array[$i + 1];
} else {
$compare = $callback($array[$i], $array[$i + 1]);
}
if ($compare > 0) {
$is_sorted = false;
$errors[] = "인덱스 $i: {$array[$i]} > {$array[$i + 1]}";
}
}
if ($is_sorted) {
echo "✓ 정렬이 올바르게 되었습니다.\n";
} else {
echo "✗ 정렬 오류 발견:\n";
foreach ($errors as $error) {
echo " - $error\n";
}
}
return $is_sorted;
}
/**
* 정렬 성능 비교
*/
public static function compareSortPerformance($array, $methods) {
echo "정렬 성능 비교 (배열 크기: " . count($array) . "):\n";
foreach ($methods as $name => $callback) {
$test_array = $array; // 복사본 생성
$start_time = microtime(true);
$start_memory = memory_get_usage();
$callback($test_array);
$end_time = microtime(true);
$end_memory = memory_get_usage();
$time_taken = round(($end_time - $start_time) * 1000, 2);
$memory_used = round(($end_memory - $start_memory) / 1024, 2);
echo "- $name: {$time_taken}ms, {$memory_used}KB\n";
}
}
}
// 디버깅 예제
echo "정렬 디버깅 예제:\n\n";
// 1. 잘못된 비교 함수 예제
echo "1. 잘못된 비교 함수:\n";
$wrong_callback = function($a, $b) {
// 잘못된 예: 일관성 없는 비교
if ($a == $b) return 1; // 같을 때 0이 아닌 1 반환
return $a <=> $b;
};
SortingDebugger::validateSortFunction($wrong_callback);
// 2. 올바른 비교 함수
echo "\n2. 올바른 비교 함수:\n";
$correct_callback = function($a, $b) {
return $a <=> $b;
};
SortingDebugger::validateSortFunction($correct_callback);
// 3. 정렬 결과 검증
echo "\n3. 정렬 결과 검증:\n";
$test_array = [3, 1, 4, 1, 5, 9, 2, 6];
sort($test_array);
SortingDebugger::verifySortResult($test_array);
// 잘못 정렬된 배열 테스트
$wrong_sorted = [1, 3, 2, 4, 5];
echo "\n잘못 정렬된 배열 검증:\n";
SortingDebugger::verifySortResult($wrong_sorted);
// 4. 성능 비교
echo "\n4. 정렬 방법별 성능 비교:\n";
$performance_test_array = [];
for ($i = 0; $i < 10000; $i++) {
$performance_test_array[] = rand(1, 1000);
}
$sort_methods = [
'sort()' => function(&$arr) { sort($arr); },
'usort() 기본' => function(&$arr) {
usort($arr, function($a, $b) { return $a <=> $b; });
},
'array_multisort()' => function(&$arr) {
array_multisort($arr, SORT_NUMERIC, SORT_ASC);
}
];
SortingDebugger::compareSortPerformance($performance_test_array, $sort_methods);
?>
| 함수 | 용도 | 키 보존 | 정렬 기준 |
|---|---|---|---|
sort() | 기본 오름차순 | ❌ | 값 |
rsort() | 기본 내림차순 | ❌ | 값 |
asort() | 연관배열 오름차순 | ✅ | 값 |
arsort() | 연관배열 내림차순 | ✅ | 값 |
ksort() | 키 기준 오름차순 | ✅ | 키 |
krsort() | 키 기준 내림차순 | ✅ | 키 |
usort() | 사용자 정의 | ❌ | 사용자 함수 |
uasort() | 사용자 정의 (키 보존) | ✅ | 사용자 함수 |
uksort() | 키 기준 사용자 정의 | ✅ | 사용자 함수 |
natsort() | 자연 정렬 | ✅ | 자연순서 |
usort() 사용 시 일관성 있는 비교 함수 작성