LINQ가 유용하다고 느끼게 된 일
제가 요즘 알고리즘 문제 풀이에 도전하고 있는데 C#으로 해보고 있습니다.
우주선이 산에 충돌하지 않도록 가장 높은 산부터 차례대로 파괴하는 문제입니다.
8개의 산은 왼쪽부터 0~7번의 인덱스를 가지고 인덱스를 출력하면 산에 발포하여 산을 파괴하는 문제였습니다.
using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
/**
* The while loop represents the game.
* Each iteration represents a turn of the game
* where you are given inputs (the heights of the mountains)
* and where you have to print an output (the index of the mountain to fire on)
* The inputs you are given are automatically updated according to your last actions.
**/
class Player
{
static void Main(string[] args)
{
// game loop
while (true)
{
int max_h = 0;
int max_index = 0;
for (int i = 0; i < 8; i++)
{
int mountainH = int.Parse(Console.ReadLine()); // represents the height of one mountain.
if (mountainH > max_h)
{
max_h = mountainH;
max_index = i;
}
}
// Write an action using Console.WriteLine()
// To debug: Console.Error.WriteLine("Debug messages...");
Console.WriteLine(max_index); // The index of the mountain to fire on.
}
}
}
저는 처음에 그냥 간단하게 산의 높이와 위치를 구하기 위해 변수 두 개를 만들고 for문 안에 산의 높이 즉, 숫자가 입력될 때마다 변수보다 숫자가 큰 산의 숫자와 인덱스를 변수에 담고 다 끝나면 가장 높은 산의 인덱스(위치)를 출력해서 풀었는데요.
가장 높은 추천을 받은 코드를 보니 LINQ를 써서 너무나 짧고 명쾌하게 풀었더군요.
class Player
{
static void Main(string[] args)
{
var range = Enumerable.Range(0, 8);
// game loop
while (true)
{
var mountains = range.Select(x => int.Parse(Console.ReadLine())).ToList();
Console.WriteLine(mountains.IndexOf(mountains.Max()));
}
}
}
제 함수를 보고 이 함수를 본 순간 LINQ가 생각보다 더 좋아보여 공부할 겸 블로그에 소개해보겠습니다..
C# 언어의 LINQ(Language-Integrated Query)는 데이터베이스와 같은 데이터 소스에서 데이터를 검색, 추출, 조작하는 기능을 제공하는 쿼리 기능입니다. 이를 통해 반복문을 줄일 수 있고 가독성이 좋아집니다.
System.Linq.Enumerable는 C# 언어의 LINQ의 핵심 기능을 제공하는 클래스입니다. Enumerable 클래스는 배열, 리스트, 집합, 딕셔너리 등과 같은 컬렉션에 대한 다양한 확장 메소드를 제공합니다.
Enumerable 클래스에는 여러 가지 유용한 메소드가 있습니다. 다음은 일부 예시입니다.
- Select: 지정된 함수를 사용하여 시퀀스의 각 요소를 새로운 형식으로 변환합니다.
- Where: 지정된 조건에 따라 시퀀스의 요소를 필터링합니다.
- OrderBy / OrderByDescending: 시퀀스의 요소를 오름차순 또는 내림차순으로 정렬합니다.
- Count: 시퀀스의 요소 수를 반환합니다.
또한, Enumerable 클래스에는 Range, Repeat, Empty 등과 같은 정적 메소드도 있습니다. 이러한 메소드를 사용하면 더 간단하게 배열을 생성하거나 반복문을 구현할 수 있습니다.
먼저 정적 메소드에 대해 살펴보자면
- Range: 지정된 범위 내의 숫자 시퀀스를 생성합니다. 주어진 시작값과 끝값 사이의 연속된 정수를 반환합니다.
var range = Enumerable.Range(1, 5); // 1, 2, 3, 4, 5
- Repeat: 지정된 값으로 구성된 반복된 시퀀스를 생성합니다.
var repeat = Enumerable.Repeat("hello", 3); // "hello", "hello", "hello"
- Empty: 지정된 유형에 대한 비어있는 시퀀스를 생성합니다.
var empty = Enumerable.Empty<int>(); // {}
이러한 정적 메소드를 사용하면 다양한 데이터 타입의 컬렉션을 더 쉽게 생성하고 초기화할 수 있습니다.
그러면 데이터를 다루는 아까 전에 본 유용한 메소드들을 예시 코드와 함께 보겠습니다.
지금 보시는 예시는 LINQ의 메서드 구문입니다. 쿼리 구문이랑 의미상으로는 동일합니다.
LINQ의 쿼리 구문 및 메서드 구문(C#)
LINQ의 쿼리 구문 및 메서드 구문에 대해 알아봅니다. 여기에는 표준 쿼리 연산자 확장 메서드 및 람다 식이 포함됩니다.
learn.microsoft.com
1. Select 예시
컬렉션의 모든 요소를 지정된 함수에 따라 변환하여 새로운 컬렉션을 만듭니다.
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
var squaredList = list.Select(x => x * x);
foreach (var item in squaredList)
{
Console.WriteLine(item);
}
위 코드는 리스트에 있는 모든 요소를 제곱한 값을 새로운 리스트로 반환합니다. Select 메서드는 매개변수로 전달된 람다식을 사용하여 시퀀스의 각 요소를 새로운 형식으로 변환합니다. 이 경우에는 각 요소를 제곱한 값으로 변환합니다. 변환된 값은 IEnumerable<T> 형식의 시퀀스로 반환되며, 이를 다시 리스트로 변환하여 squaredList 변수에 저장합니다. 이후 foreach문을 사용하여 squaredList의 각 요소를 출력합니다.
2. Where 예시
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
List<int> evenNumbers = list.Where(n => n % 2 == 0).ToList();
// evenNumbers: {2, 4}
위 코드는 Where 함수를 사용하여 list에서 짝수만 필터링한 후 새로운 리스트인 evenNumbers에 저장합니다.
3. OrderBy / OrderByDescending 예시
List<int> list = new List<int> { 3, 1, 4, 1, 5, 9, 2, 6 };
List<int> ascendingList = list.OrderBy(n => n).ToList();
// ascendingList: {1, 1, 2, 3, 4, 5, 6, 9}
List<int> descendingList = list.OrderByDescending(n => n).ToList();
// descendingList: {9, 6, 5, 4, 3, 2, 1, 1}
위 코드는 OrderBy 함수와 OrderByDescending 함수를 사용하여 list를 오름차순으로 정렬한 ascendingList와 내림차순으로 정렬한 descendingList를 각각 생성합니다.
4. Count 예시
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
int count = list.Count();
// count: 5
Count 함수는 시퀀스(컬렉션)의 요소 수를 반환합니다.
Count 함수는 매개변수를 가지며, 매개변수로는 Func<TSource, bool> 형식의 predicate 함수를 전달할 수 있습니다. predicate 함수는 시퀀스의 각 요소에 대해 호출되며, 조건을 만족하는 요소의 수를 반환합니다. 예를 들어, 다음은 리스트 list에서 짝수인 요소의 수를 반환하는 코드입니다.
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
int evenCount = list.Count(n => n % 2 == 0);
// evenCount: 2
위 코드에서 n => n % 2 == 0 부분이 predicate 함수입니다. 이 함수는 시퀀스의 각 요소 n에 대해, n이 2로 나누어 떨어지는지 검사하여 true 또는 false를 반환합니다. Count 함수는 predicate 함수를 시퀀스의 각 요소에 대해 호출하여 조건을 만족하는 요소의 수를 반환합니다.
'C# 프로그래밍' 카테고리의 다른 글
[C#] 네트워크 프로그래밍 (0) | 2023.04.06 |
---|---|
[C#] TCP/IP 네트워크 (2) (0) | 2023.03.29 |
[C#] TCP/IP 네트워크 (1) (1) | 2023.03.28 |
[C#] async 한정자와 await 연산자 (0) | 2023.03.28 |
[C#] task (2) (0) | 2023.03.27 |