델리게이트를 활용한 배열 메서드 구현 연습문제 이해해보기

공재원
∙∙조회 2

문제 설명

델리게이트를 매개변수로 받아 int 배열을 처리하는 MyArray 클래스의 정적 메서드들을 구현하고, 사용자가 입력한 점수에 적용하는 프로그램을 작성하는 문제임.

1. 사용할 델리게이트 타입

.NET이 제공하는 델리게이트 타입에 타입 인자로 int를 넘겨 사용함.

타입매개변수반환용도
Action<int>intvoid요소마다 작업 수행
Predicate<int>intbool조건 검사
Func<int, int>intint요소 변환
Func<int, int, int>int, intint두 요소 비교

2. MyArray 정적 메서드 구현

  1. ForEach(int[] array, Action<int> action)
  • 모든 요소에 대해 앞에서부터 차례로 action을 호출함
  1. Count(int[] array, Predicate<int> match)
  • match가 true를 반환하는 요소의 개수를 반환함
    • 예: [1,2,3,4], 짝수 조건 -> 2
  1. Exists(int[] array, Predicate<int> match)
  • match를 만족하는 요소가 하나라도 있으면 true를 반환함
  1. FindIndex(int[] array, Predicate<int> match)
  • match를 만족하는 첫 번째 요소의 인덱스를 반환함
    • 찾지 못하면 -1 반환
    • 예: [5,8,3,10], 7보다 큼 -> 1
  1. Filter(int[] array, Predicate<int> match)
  • match를 만족하는 요소만 원래 순서대로 담은 새 배열을 반환함
    • 원본 배열은 바꾸지 않음
    • 반환 배열의 길이는 만족하는 요소의 개수와 같음
    • 예: [1,2,3,4,5], 홀수 조건 -> [1,3,5]
  1. Transform(int[] array, Func<int, int> transformer)
  • 각 요소를 transformer의 반환값으로 바꿈 (원본 배열을 직접 수정)
    • 예: [1,2,3], 두 배 -> [2,4,6]
  1. Sort(int[] array, Func<int, int, int> comparison)
  • 버블 정렬로 배열을 정렬함
    • comparison(x, y)가 양수이면 x를 y보다 뒤에, 음수이면 앞에 두는 것으로 판단함
    • 예: [3,1,2], (x, y) => y - x -> [3,2,1]
markdown
### 버블 정렬 알고리즘

1. 배열의 앞에서부터 이웃한 두 원소를 비교함
2. 앞 원소가 뒤 원소보다 크면 두 원소를 교환함
3. 끝까지 비교하면 1회차가 끝나며, 가장 큰 값이 맨 뒤로 이동함
4. 맨 뒤에 확정된 원소를 제외하고 1~3을 반복함
5. 회차는 모두 원소 수 - 1번 수행함

3. 점수 처리 프로그램

  • 공백으로 구분한 점수(0~100의 정수)를 한 줄로 입력받아 int 배열을 만듦
  • 입력받은 배열로 다음 항목을 차례로 출력함. 각 항목은 괄호 안의 MyArray 메서드에 람다식을 전달하여 구함
    1. 입력한 점수를 점을 붙여 나열 (ForEach)
    2. 60점 이상인 인원 (Count)
    3. 100점이 있는지 여부 (Exists)
    4. 90점 이상인 첫 점수의 위치, 없으면 없음 (FindIndex)
    5. 60점 이상인 점수 (Filter)
    6. 짝수인 점수 (Filter) — 람다식 대신 짝수 여부를 반환하는 메서드를 만들어 메서드 이름을 전달함
    7. 5번 결과에 5점을 더한 보정 점수, 100점을 넘으면 100점 (Transform)
    8. 보정 점수를 내림차순으로 정렬한 결과 (Sort)
  • 배열은 [a, b, c] 형식으로 출력함

제약사항

  1. 컬렉션과 System.Array의 메서드는 사용하지 않음
  2. 입력은 형식에 맞는 값만 들어온다고 가정하며, 예외 처리는 생략함

입력 예시 1

plain text
72 95 48 100 60 91 55

출력 예시 1

ini
점수 입력: 72 95 48 100 60 91 55
입력한 점수: 72점 95점 48점 100점 60점 91점 55점
60점 이상 인원: 5명
만점 존재 여부: True
첫 90점 이상 위치: 1
60점 이상 점수: [72, 95, 100, 60, 91]
짝수 점수: [72, 48, 100, 60]
보정 점수: [77, 100, 100, 65, 96]
보정 점수 내림차순: [100, 100, 96, 77, 65]


1. 문제의 핵심

이 문제는 MyArray 클래스에 배열을 처리하는 정적 메서드를 구현하고, 델리게이트와 람다식을 전달하여 점수 배열을 처리하는 문제다.

핵심 학습 내용은 다음과 같다.

  • 델리게이트: 메서드를 전달하는 기능
  • 람다식: 메서드를 간단하게 표현하는 문법
  • 배열 처리: 요소를 순회하고, 개수를 세고, 조건에 맞는 요소를 찾는 작업
  • 배열 변환: 배열의 각 요소를 새로운 값으로 변경하는 작업
  • 버블 정렬: 이웃한 두 요소를 비교하고 교환하여 배열을 정렬하는 알고리즘

2. 델리게이트

델리게이트는 메서드를 참조하고 전달할 수 있는 타입이다.

메서드를 직접 호출하는 대신 다른 메서드에 전달하여 필요한 시점에 실행할 수 있다.

2-1. 주요 델리게이트 타입

델리게이트매개변수반환형역할
Action<int>int 1개void작업 수행
Predicate<int>int 1개bool조건 검사
Func<int, int>int 1개int값 변환
Func<int, int, int>int 2개int두 값 비교

2-2. Action

Action<int>는 정수 하나를 전달받아 작업을 수행하는 델리게이트다.

  • 반환값이 필요 없는 작업에 사용한다.
  • 배열의 각 점수에 점을 붙여 출력하는 작업에 활용한다.

2-3. Predicate

Predicate<int>는 정수 하나를 전달받아 조건을 검사하고 true 또는 false를 반환한다.

  • 조건에 맞는 요소를 찾을 때 사용한다.
  • 60점 이상인지, 짝수인지 등을 검사하는 데 활용한다.

2-4. Func

Func<int, int>는 정수 하나를 전달받아 정수를 반환한다.

  • 값을 변환할 때 사용한다.
  • 점수에 5점을 더하는 작업 등에 활용한다.

Func<int, int, int>는 정수 두 개를 전달받아 정수를 반환한다.

  • 두 요소를 비교할 때 사용한다.
  • 정렬 순서를 결정하는 데 활용한다.

기억할 점

Action은 작업, Predicate는 조건, Func는 반환값이 있는 작업에 사용한다.


3. 람다식

람다식은 메서드를 간결하게 표현하는 문법이다.

3-1. 람다식의 기본 형태

매개변수 => 실행할 내용

  • => 왼쪽: 매개변수
  • => 오른쪽: 실행할 내용 또는 반환할 값

3-2. 람다식의 역할

목적조건 또는 작업
점수 출력점수 뒤에 점을 붙임
조건 검사60점 이상인지 확인
조건 검사100점인지 확인
조건 검사90점 이상인지 확인
값 변환점수에 5점을 더하고 100점으로 제한
값 비교내림차순 정렬을 위한 비교

람다식은 전달받은 값을 어떻게 처리할지 나타낸다.

실제로 배열을 순회하거나 정렬하는 작업은 MyArray의 메서드가 담당하고, 람다식은 각 메서드에 처리 기준을 전달한다.


4. MyArray의 정적 메서드

정적 메서드는 객체를 생성하지 않고 클래스 이름으로 호출할 수 있는 메서드다.

이 문제에서는 배열을 처리하는 기능을 MyArray 클래스에 모아 구현한다.

4-1. ForEach

역할: 배열의 모든 요소를 앞에서부터 차례로 처리한다.

  • 델리게이트: Action<int>
  • 반환값: 없음
  • 배열 변경: 전달한 작업에 따라 달라짐

점수 뒤에 점을 붙여 출력하는 작업에 사용한다.

4-2. Count

역할: 조건을 만족하는 요소의 개수를 반환한다.

  • 델리게이트: Predicate<int>
  • 반환값: int
  • 배열 변경: 하지 않음

60점 이상인 점수가 몇 개인지 계산할 때 사용한다.

4-3. Exists

역할: 조건을 만족하는 요소가 하나라도 있는지 확인한다.

  • 델리게이트: Predicate<int>
  • 반환값: bool
  • 배열 변경: 하지 않음

100점이 존재하는지 확인할 때 사용한다.

4-4. FindIndex

역할: 조건을 만족하는 첫 번째 요소의 인덱스를 반환한다.

  • 델리게이트: Predicate<int>
  • 반환값: int
  • 배열 변경: 하지 않음
  • 조건에 맞는 요소가 없으면 -1을 반환한다.

90점 이상인 첫 번째 점수의 위치를 찾을 때 사용한다.

인덱스는 0부터 시작한다.

예를 들어 첫 번째 요소의 인덱스는 0, 두 번째 요소의 인덱스는 1이다.

4-5. Filter

역할: 조건을 만족하는 요소만 새 배열에 담아 반환한다.

  • 델리게이트: Predicate<int>
  • 반환값: int[]
  • 배열 변경: 원본 배열은 변경하지 않음

60점 이상인 점수나 짝수인 점수만 추출할 때 사용한다.

반환 배열에는 조건을 만족하는 요소만 들어간다.

4-6. Transform

역할: 배열의 각 요소를 변환한다.

  • 델리게이트: Func<int, int>
  • 반환값: 없음
  • 배열 변경: 원본 배열을 직접 수정한다.

각 점수에 5점을 더하거나, 100점을 넘지 않도록 보정할 때 사용한다.

주의: 이 문제의 Transform은 새 배열을 반환하는 것이 아니라 기존 배열의 요소를 변경한다.

4-7. Sort

역할: 비교 기준에 따라 배열을 정렬한다.

  • 델리게이트: Func<int, int, int>
  • 반환값: 없음
  • 배열 변경: 원본 배열을 직접 정렬한다.
  • 정렬 방식: 버블 정렬

비교 함수의 반환값에 따라 요소의 순서를 결정한다.

비교 결과의미
양수첫 번째 요소를 두 번째 요소보다 뒤에 배치
음수첫 번째 요소를 두 번째 요소보다 앞에 배치
0두 요소의 순서를 바꿀 필요가 없음

비교 기준을 어떻게 작성하는지에 따라 오름차순과 내림차순을 구현할 수 있다.


5. 배열 처리 메서드 비교

메서드핵심 기능원본 배열 변경
ForEach모든 요소에 작업 수행작업에 따라 다름
Count조건을 만족하는 요소의 개수 계산아니요
Exists조건을 만족하는 요소가 있는지 확인아니요
FindIndex조건을 만족하는 첫 번째 인덱스 검색아니요
Filter조건에 맞는 요소만 새 배열로 추출아니요
Transform각 요소의 값 변환예
Sort비교 기준에 따라 정렬예

특히 Filter, Transform, Sort의 차이를 구분해야 한다.

  • Filter: 조건에 맞는 요소만 새 배열에 담는다.
  • Transform: 원본 배열의 요소를 직접 변경한다.
  • Sort: 원본 배열의 요소 순서를 변경한다.

6. 버블 정렬

버블 정렬은 배열에서 이웃한 두 요소를 비교하고, 순서가 잘못되었으면 교환하는 정렬 알고리즘이다.

6-1. 동작 원리

  1. 배열의 앞에서부터 이웃한 두 요소를 비교한다.
  2. 비교 결과에 따라 두 요소의 순서를 교환한다.
  3. 배열의 끝까지 비교하면 한 회차가 끝난다.
  4. 정렬이 완료된 끝부분을 제외하고 다음 회차를 진행한다.
  5. 일반적으로 배열의 요소가 N개라면 최대 N-1회차를 수행한다.

6-2. 오름차순과 내림차순

  • 오름차순: 작은 값부터 큰 값 순서로 정렬한다.
  • 내림차순: 큰 값부터 작은 값 순서로 정렬한다.

정렬 알고리즘은 같아도 비교 기준에 따라 정렬 결과가 달라진다.

핵심: 버블 정렬은 이웃한 두 요소를 비교하고 필요하면 교환하는 과정을 반복한다.


7. 점수 처리 프로그램의 실행 순서

입력 점수가 다음과 같다고 가정한다.

72 95 48 100 60 91 55

1단계. 입력한 점수 출력

ForEach를 사용하여 모든 점수 뒤에 점을 붙여 출력한다.

2단계. 60점 이상인 인원 계산

Count를 사용하여 60점 이상인 요소의 개수를 계산한다.

결과: 5명

3단계. 만점 존재 여부 확인

Exists를 사용하여 100점인 요소가 있는지 확인한다.

결과: True

4단계. 첫 90점 이상 위치 찾기

FindIndex를 사용하여 90점 이상인 첫 번째 요소의 인덱스를 찾는다.

첫 번째 90점 이상인 점수는 95점이며, 인덱스는 1이다.

5단계. 60점 이상인 점수 추출

Filter를 사용하여 60점 이상인 점수만 새 배열로 만든다.

결과: [72, 95, 100, 60, 91]

6단계. 짝수 점수 추출

Filter에 짝수 여부를 검사하는 메서드를 전달한다.

결과: [72, 48, 100, 60]

7단계. 보정 점수 계산

5단계에서 얻은 배열의 각 점수에 5점을 더한다.

단, 100점을 초과하면 100점으로 제한한다.

결과: [77, 100, 100, 65, 96]

8단계. 보정 점수 내림차순 정렬

Sort를 사용하여 보정 점수를 큰 값부터 작은 값 순서로 정렬한다.

결과: [100, 100, 96, 77, 65]


8. 배열을 출력하는 방법

배열을 [a, b, c] 형식으로 출력하려면 배열 요소 사이에 쉼표와 공백을 넣어 문자열로 연결하면 된다.

반면 점수 뒤에 점을 붙여 출력할 때는 각 요소를 순회하면서 출력 작업을 수행한다.

두 방식의 차이는 다음과 같다.

  • string.Join: 배열 요소를 지정한 구분자로 연결한다.
  • ForEach: 각 요소에 지정한 작업을 수행한다.

배열을 보기 좋은 문자열로 출력하는 것과 배열의 요소를 하나씩 처리하는 것은 서로 다른 작업이다.


9. 자주 헷갈리는 부분

Q1. Action과 Predicate의 차이는?

Action은 작업을 수행하고 값을 반환하지 않는다. Predicate는 조건을 검사하여 true 또는 false를 반환한다.

Q2. Predicate와 Func의 차이는?

Predicate는 조건 검사에 사용하며 반환형이 bool이다. Func는 지정된 반환형의 값을 반환한다.

Q3. Filter와 Transform의 차이는?

Filter는 조건에 맞는 요소만 새 배열로 추출한다. Transform은 기존 배열의 요소를 직접 변경한다.

Q4. FindIndex에서 -1을 반환하는 이유는?

조건을 만족하는 요소가 없다는 것을 나타내기 위해서다.

Q5. Sort에 비교 함수를 전달하는 이유는?

요소를 어떤 기준으로 정렬할지 결정하기 위해서다. 비교 함수의 반환값에 따라 요소의 순서를 결정한다.

Q6. 람다식과 메서드 이름을 전달하는 것은 어떻게 다른가?

람다식은 필요한 동작을 직접 표현할 수 있다. 이미 정의된 메서드가 있다면 그 메서드를 델리게이트에 전달하여 재사용할 수도 있다.


오늘은 직접 코드를 작성한 부분은 많이 없고 선생님과 작성한 코드가 대부분이다.
그렇기에 코드를 리뷰를 작성하기 보다는 델리게이트를 이해해보는 시간을 가져보려고 하였다.
코드 리뷰는 해당 문서에서 작성하지는 않고 따로 리뷰 할 생각이다.