[복습] 261028 - 정렬과 델리게이트
방향성 변화: 문제 못풀어도 포기하지말고 중간 과정에서 얻어가기로함
문제 설명
델리게이트를 매개변수로 받아 int 배열을 처리하는 MyArray 클래스의 정적 메서드들을 구현하고, 사용자가 입력한 점수에 적용하는 프로그램을 작성하는 문제임.
1. 사용할 델리게이트 타입
.NET이 제공하는 델리게이트 타입에 타입 인자로 int를 넘겨 사용함.
| 타입 | 매개변수 | 반환 | 용도 |
|---|---|---|---|
Action<int> | int | void | 요소마다 작업 수행 |
Predicate<int> | int | bool | 조건 검사 |
Func<int, int> | int | int | 요소 변환 |
Func<int, int, int> | int, int | int | 두 요소 비교 |
2. MyArray 정적 메서드 구현
ForEach(int[] array, Action<int> action)
- 모든 요소에 대해 앞에서부터 차례로 action을 호출함
Count(int[] array, Predicate<int> match)
- match가 true를 반환하는 요소의 개수를 반환함
- 예: [1,2,3,4], 짝수 조건 -> 2
Exists(int[] array, Predicate<int> match)
- match를 만족하는 요소가 하나라도 있으면 true를 반환함
FindIndex(int[] array, Predicate<int> match)
- match를 만족하는 첫 번째 요소의 인덱스를 반환함
- 찾지 못하면 -1 반환
- 예: [5,8,3,10], 7보다 큼 -> 1
Filter(int[] array, Predicate<int> match)
- match를 만족하는 요소만 원래 순서대로 담은 새 배열을 반환함
- 원본 배열은 바꾸지 않음
- 반환 배열의 길이는 만족하는 요소의 개수와 같음
- 예: [1,2,3,4,5], 홀수 조건 -> [1,3,5]
Transform(int[] array, Func<int, int> transformer)
- 각 요소를 transformer의 반환값으로 바꿈 (원본 배열을 직접 수정)
- 예: [1,2,3], 두 배 -> [2,4,6]
Sort(int[] array, Func<int, int, int> comparison)
- 버블 정렬로 배열을 정렬함
- comparison(x, y)가 양수이면 x를 y보다 뒤에, 음수이면 앞에 두는 것으로 판단함
- 예: [3,1,2], (x, y) => y - x -> [3,2,1]
using System;
//using MyArray;
Console.Write("점수 입력: ");
//원하는만큼 입력함
//int[] Array Count = { int.Parse(Console.ReadLine()) };//안되네
//int[] MyArray.ForEach = { int.Parse(Console.ReadLine()) };// 이건가
int[] array = { 72, 95, 48, 100, 60, 91, 55 };
MyArray.ForEach(array, x => Console.Write($"{x} "));
Console.WriteLine();
//MyArray.MyArray.ForEach(array, x => Console.Write($"입력한 점수: {x}점"));
//출력: 입력한 점수: n점 n점 n점 n점 n점 n점 n점
Console.Write("입력한 점수: ");
MyArray.ForEach(array, x => Console.Write($"{x}점 "));
Console.WriteLine();
//출력: mm점 이상 인원: n명
Console.Write("60점 이상 인원: ");
int overCount = MyArray.Count(array, c => c >= 60);//5. 갑자기 bool? 이라면서 인식못함
//Console.Write($"{MyArray.Count(array, c => c >= 60)}");
Console.Write($"{overCount}명"); //이렇게 해도 됨
Console.WriteLine();
//출력: 만점 존재 여부: True
bool is100 = MyArray.Exists(array, h => h == 100);
Console.Write($"만점 존재 여부: {is100}");
Console.WriteLine();
//첫 90점 이상 위치:
int overIndex = MyArray.FindIndex(array, i => i >= 90);
Console.Write($"첫 90점 이상 위치: {overIndex}");
Console.WriteLine();
//60점 이상 점수:
int[] over60Index = MyArray.Filter(array, s => s >= 60);
Console.Write($"60점 이상 점수: [{string.Join(", ", over60Index)}]");
Console.WriteLine();
//짝수 점수:
int[] isEven = MyArray.Filter2(array, e => e % 2 == 0);
Console.Write($"짝수 점수: [{string.Join(", ", isEven)}]");
Console.WriteLine();
//보정 점수:
MyArray.Transform(array, t => Math.Min(t + 5, 100));
Console.Write($"보정 점수: [{string.Join(", ", array)}]");
//여기서는 Transform()이 기존 array를 수정하므로, 결과를 출력할 때도 array를 사용해
//그러네 ㅁㅊ
static bool IsEven(int value)
{
return value % 2 == 0;
}
int[] passed = MyArray.Filter(array, x => x >= 60);
passed = MyArray.Filter(passed, IsEven);
Console.WriteLine();
//보정 점수 내림차순:
MyArray.Sort(passed, (a, b) => b.CompareTo(a)) ; //내림차순이라 a b 바뀜 a-b도 되는데 이게 지금께 좋음
Console.Write($"보정 점수 내림차순: [{string.Join(", ", passed)}]");
using System;
//namespace MyArray
//{
//}
internal class MyArray
{
//1. `ForEach(int[] array, Action<int> action)`
//- 모든 요소에 대해 앞에서부터 차례로 action을 호출함
public static void ForEach(int[] array, Action<int> action)
{
foreach (int number in array)
{
action(number);//호출
//Console.WriteLine($"입력한 점수: {string.Join("점 ", array)}");//점수 뒤에 점 을 붙임 Join 키워드?
}
}
//2. `Count(int[] array, Predicate<int> match)`
//- match가 true를 반환하는 요소의 개수를 반환함
//-예: [1, 2, 3, 4], 짝수 조건 -> 2
//array c 배열값이 들어옴
public static int Count(int[] array, Predicate<int> match)
{
//1. match 조건을 어디서 계산해야하지
//2. 지금 match가 설정만 되있지 조건이 없음
int count = 0;
foreach (int number in array)
{
//if (match(number % 2 == 0)) //3. 근데 조건값을 설정할수 없음
//isEven같은 함수가 안먹힘 다른 계산 불가
//조건식도 불가
if (match(number))
{
count++;
}
}
return count;//4. 그리고 분명 int 반환인데
}
//3.
public static bool Exists(int[] array, Predicate<int> match)
{
foreach (int number in array)
{
if (match(number))
{
return true;
}
}
return false;
}
//4.
public static int FindIndex(int[] array, Predicate<int> match)
{
for (int number = 0; number < array.Length; number++)
{
if (match(array[number]))//반복 배열 넣음
{
return number; //인덱스 리턴
}
}
return -1;
}
public static int[] Filter(int[] array, Predicate<int> match)
{
//새 배열을 반환함
int count = 0;
for (int i = 0; i < array.Length; i++)
{
if (match(array[i])) //맞는지 계산
{
count++;//맞는게 두개니까 두번 더해지면
}
}
int[] over60 = new int[count];//2칸생성?
int index = 0;
for (int i = 0; i < array.Length; i++)
{
if (match(array[i])) //맞는지 계산
{
over60[index] = array[i]; //원본 배열의 값을 새 배열의 빈자리에 넣기
index++;//다음값 넣을 위치로 이동
}
}
return over60;
}
public static int[] Filter2(int[] array, Predicate<int> match)
{
//새 배열을 반환함
int index = 0;
int[] result = new int[Count(array, match)];
for (int i = 0; i < array.Length; i++)
{
if (match(array[i])) //맞는지 계산
{
//count++;//맞는게 두개니까 두번 더해지면
result[index++] = array[i];
}
}
return result;
}
public static void Transform(int[] array, Func<int, int> transformer)
{
//length = 7
//0~6
//transformer엔 무슨수가 들어올까...
for (int i = 0; i < array.Length; i++)
{
array[i] = transformer(array[i]);
}
}
public static void Sort(int[] array, Func<int, int, int> comparison)
{
//이중반복문
//왜 Length에 -1을하지?
//그럼 6개인데
//출력은 5개만되고
//사실그거보단 일부 숫자가 씹히는게 더 문제다
for(int i = 0;i < array.Length-1; i++)
{
//i는 6번 돌아
//(a, b) => b.CompareTo(a)) 한게 comparison에 들어오나?
//근대 비교를 뭐 어떻게 하는거고 한게 어떻게 나오는건데
//큰게나오는거야?
for (int j = 0; j <array.Length-1; j++)
{
//95 72 - 왼쪽이 오른쪽보다 큼 -> 양수
//1
//
if(comparison(array[j], array[j+1])>0)
{
int temp = array[j];
array[j] = array[j + 1];
array[j+1] = temp;
}
}
}
}
}

- 문제를 다 이해하지 못했으나 후반부 작은 문제 이해 시도
배운내용
Func<T, TResult>
메서드를 참조하고 전달할 수 있는 함수 타입. 입력 매개변수와 반환 타입을 지정한다.
기본 형태
Func<입력타입, 반환타입> 변수명;
Func에서 마지막 타입이 반환 타입이야.
예시
Func<int, int> doubleNumber = x => x * 2;
int result = doubleNumber(5); // 10
- 첫 번째
int: 입력 타입 - 두 번째
int: 반환 타입 x => x 2: 입력받은 숫자에 2를 곱하는 함수doubleNumber(5): 함수를 실행하고 결과를 반환
사용 방법
Func<int, int, int> add = (a, b) => a + b;
int result = add(3, 5); // 8
- 입력값이 2개이고 반환값이 정수 1개인 함수야.
응용
static int Transform(int[] array, Func<int, int> action)
{
for (int i = 0; i < array.Length; i++)
{
array[i] = action(array[i]);
}
return array.Length;
}
이처럼 함수 자체를 매개변수로 전달하면, 실행할 동작을 외부에서 바꿀 수 있어.
CompareTo()
두 값을 비교하여 음수, 0, 양수 중 하나의 결과를 반환
기본 형태
기준값.CompareTo(비교할값);
예시
int a = 72;
int b = 95;
int result = a.CompareTo(b);
| 코드 | 결과의 의미 |
|---|---|
72.CompareTo(95) | 음수 |
95.CompareTo(72) | 양수 |
95.CompareTo(95) | 0 |
- 왼쪽이 오른쪽보다 크면 참 (바꿈)
- 작으면 거짓 (안바꿈)
반환값이 반드시 -1, 0, 1인 것은 아니야. 음수인지, 0인지, 양수인지를 구분하는 게 중요해.
사용 방법
if (a.CompareTo(b) < 0)
{
// a가 b보다 작은 경우
}
응용: 정렬 방향 결정
// 오름차순
(a, b) => a.CompareTo(b)
// 내림차순
(a, b) => b.CompareTo(a)
비교 순서를 반대로 하면 정렬 방향을 바꿀 수 있어.
Sort()
배열의 요소를 지정한 기준에 따라 순서대로 배치하는 메서드. 아래 예시는 버블 정렬을 직접 구현한 것이다.
- 여기서
Sort()는 C#에 이미 존재하는 특정 메서드를 가리키는 게 아니라, 우리가 직접 만든 메서드야. C#에는 별도로Array.Sort()도 있음
기본 형태
static void Sort(
int[] array,
Func<int, int, int> comparison)
| 매개변수 | 의미 |
|---|---|
int[] array | 정렬할 정수 배열 |
Func<int, int, int> comparison | 두 정수를 비교하는 함수 |
void | 반환값 없이 원본 배열을 변경 |
예시
int[] numbers = { 72, 95, 30, 81 };
Sort(numbers, (a, b) => b.CompareTo(a));
결과:
95, 81, 72, 30
사용 방법
if (comparison(array[j], array[j + 1]) > 0)
{
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
- 인접한 두 값을 비교한다.
- 비교 결과가 양수이면 교환한다.
- 반복하면서 배열을 정렬한다.
응용
// 오름차순 정렬
Sort(numbers, (a, b) => a.CompareTo(b));
// 내림차순 정렬
Sort(numbers, (a, b) => b.CompareTo(a));
정렬 알고리즘은 유지하면서 비교 함수만 바꿔 정렬 방향을 변경할 수 있어.
temp 를 이용한 값 교환
변수의 기존 값을 임시 변수에 보관해 두 값을 서로 교환하는 방법.
기본 형태
int temp = a;
a = b;
b = temp;
예시
int a = 72;
int b = 95;
int temp = a; // temp = 72
a = b; // a = 95
b = temp; // b = 72
결과:
a = 95
b = 72
사용 방법
배열에서 인접한 두 요소를 교환할 때도 같은 원리를 사용해.
int temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
응용
- 버블 정렬에서 배열 요소 교환
- 숫자 두 개의 값 교환
- 정렬이나 재배치 알고리즘 구현
주의: 아래처럼 작성하면 첫 번째 대입에서 기존 값이 사라질 수 있어.
a = b;
b = a; // 이미 바뀐 a의 값을 다시 대입
for반복문과 배열 인덱스
반복문으로 배열의 요소를 순서대로 확인하거나 변경하는 방법.
예시
int[] numbers = { 10, 20, 30 };
for (int i = 0; i < numbers.Length; i++)
{
Console.WriteLine(numbers[i]);
}
사용 방법
i = 0: 첫 번째 인덱스부터 시작i < numbers.Length: 배열의 범위를 벗어나지 않게 반복numbers[i]: 현재 인덱스의 값에 접근
응용: 인접한 요소 비교
for (int j = 0; j < numbers.Length - 1; j++)
{
// numbers[j]와 numbers[j + 1] 비교
}
j + 1을 사용하므로 마지막 인덱스에서는 접근하면 안 돼. 따라서 numbers.Length - 1보다 작은 범위에서 반복해.
개념들이 서로 연결되는 방식
Sort()
정렬 전체를 진행
Func<int, int, int>
비교할 함수를 전달받음
CompareTo()
두 값의 비교 결과를 반환
if + temp
조건에 따라 실제 값을 교환
오늘의 성과
- Sort int 3개 오는 이유와 무엇에 대한 기능인지 이해했다!
- CompareTo 기능을 이해했다!
- Temp기능을 이해했다!



