컬렉션을 편리하게 다루기 위한 목적으로 만들어진 데이터 질의(Query)언어이다.
데이터 질의라고 하면 데이터에 대해 물어본다는 의미로 그 질문을 받은 누군가는 데이터에 대한 답변을 준다는 것이다.
여기에서 질문은 다음 내용을 포함한다.
From: 어떤 데이터 집합에서 찾을 것인가?
Where: 어떤 값의 데이터를 찾을 것인가?(조건)
Select: 어떤 항목을 추출할 것인가?
모든 LINQ 쿼리식은 반드시 from절로 시작한다. from절로 데이터 원본과 범위 변수를 지정해줘야 한다
foreach x in arr
foreach문에서 x와 같은 반복 변수를 뜻한다. from의 데이터 원본은 꼭 IEnumerable<T
> 인터페이스를 상속하는 형식이어야 한다.
from절로 데이터 원본으로부터 범위 변수를 뽑어낸 후에는 LINQ가 제공하는 수십 가지 연산자(where, orderby, select ...)를 이용해서 데이터를 가공 및 추출할 수 있다.
필터(filter)역할을 하는 연산자. from절이 데이터 원본으로부터 뽑아낸 범위 변수가 가져야 하는 조건.
위 코드를 보면 where n % 2 == 0
을 통해 나눴을 때 0이 되는 수, 즉 짝수의 조건을 넣어줬다.
데이터의 정렬을 수행하는 연산자.
기본 디폴트는 ascending 오름차순이지만, orderby n ascending
이렇게 명시해줘도 된다. 반대로 내림차순은 orderby n descending
으로 명시한다.
최종 결과를 추출하는 쿼리식의 마침표 같은 존재. var 형식으로 선언된 result의 실제 형식은 어떻게 될까? LINQ의 질의 결과는 IEnumerable<T
>로 반환되는데, 이때 형식 매개변수 T는 바로 select문에 의해 결정된다. 위 코드에서는 IEnumerable<n
>이 되는 것이다.
여러 개의 데이터 원본에 접근하려면 from문을 중첩해서 사용한다.
분류 기준에 따라 데이터를 그룹화 해주는 방법
group 범위변수 by 분류기준 into 그룹변수
각 데이터 원본에서 특정 필드의 값을 비교하여 일치하는 데이터끼리 연결한다.
= 교집합
두 데이터 원본 사이에서 일치하는 데이터들만 연결한 후 반환한다.
기준이 되는 데이터 원본의 모든 데이터를 조인 결과에 반드시 포함시킨다. 연결할 데이터 원본에 기준 데이터 원본의 데이터와 일치하는 데이터가 없다면 그 부분은 빈 값으로 결과를 채운다.
using System;
using System.Linq;
namespace LambdaTest
{
class Profile
{
public string Name { get; set; }
public int Height { get; set; }
}
class Product
{
public string Title { get; set; }
public string Star { get; set; }
}
internal class Program
{
static void Main(string[] args)
{
Profile[] arrProfile =
{
new Profile(){Name = "정우성", Height = 186},
new Profile(){Name = "김태희", Height = 158},
new Profile(){Name = "고현정", Height = 172},
new Profile(){Name = "이문세", Height = 178},
new Profile(){Name = "하하", Height = 171},
};
Product[] arrProduct =
{
new Product(){Title = "비트", Star = "정우성"},
new Product(){Title = "CF 다수", Star = "김태희"},
new Product(){Title = "아이리스", Star = "김태희"},
new Product(){Title = "모래시계", Star = "고현정"},
new Product(){Title = "Solo 예찬", Star = "이문세"},
};
//내부 조인
var listProfile = from profile in arrProfile
join product in arrProduct on profile.Name equals product.Star
select new
{
Name = profile.Name,
Work = product.Title,
Height = profile.Height
};
Console.WriteLine(" ---- 내부 조인 결과 ----");
foreach (var profile in listProfile)
{
Console.WriteLine($"이름: {profile.Name}, 작품: {profile.Work}, 키: {profile.Height}");
}
//외부 조인
listProfile = from profile in arrProfile
join product in arrProduct on profile.Name equals product.Star into ps
from product in ps.DefaultIfEmpty(new Product() { Title = "없음" })
select new
{
Name = profile.Name,
Work = product.Title,
Height = profile.Height
};
Console.WriteLine();
Console.WriteLine(" ---- 외부 조인 결과 ----");
foreach (var profile in listProfile)
{
Console.WriteLine($"이름: {profile.Name}, 작품: {profile.Work}, 키: {profile.Height}");
}
}
}
}
출처: [이것이 C#이다 3판(박상현)] 15장 연습문제
namespace LambdaTest
{
class Car
{
public int Cost { get; set; }
public int MaxSpeed { get; set; }
}
internal class Program
{
static void Main(string[] args)
{
Car[] car =
{
new Car(){Cost = 56, MaxSpeed = 120},
new Car(){Cost = 70, MaxSpeed = 150},
new Car(){Cost = 45, MaxSpeed = 180},
new Car(){Cost = 32, MaxSpeed = 200},
new Car(){Cost = 82, MaxSpeed = 280},
};
var selected = from c in car
where c.Cost >= 50 && c.MaxSpeed >= 150
select c;
foreach(var c in selected)
{
Console.WriteLine($"cost = {c.Cost}, MaxSpeed = {c.MaxSpeed}");
}
}
}
}
namespace LambdaTest
{
class Car
{
public int Cost { get; set; }
public int MaxSpeed { get; set; }
}
internal class Program
{
static void Main(string[] args)
{
Car[] cars =
{
new Car(){Cost = 56, MaxSpeed = 120},
new Car(){Cost = 70, MaxSpeed = 150},
new Car(){Cost = 45, MaxSpeed = 180},
new Car(){Cost = 32, MaxSpeed = 200},
new Car(){Cost = 82, MaxSpeed = 280},
};
var selected =
//cars.Where(c => c.Cost < 60).OrderBy(c => c.Cost);
from car in cars
where car.Cost < 60
orderby car.Cost
select car;
foreach (var c in selected)
{
Console.WriteLine($"cost = {c.Cost}, MaxSpeed = {c.MaxSpeed}");
}
}
}
}
📄참고자료
<이것이 c#이다> 3판 - 박상현 지음 (한빛미디어)
[MSDN_LINQ]