[C#] LINQ
카테고리: C Sharp
태그: Language Programming
C#의 강력한 기능중 하나인 LINQ 입니다. C#의 LINQ는 foreach … if 문으로 IEnumerable
타입을 순회할 때 작업하는 코드를 획기적으로 줄여줄 수 있습니다.
LINQ는 쿼리식의 형태와, 람다식의 형태 두가지로 존재 합니다. 이것을 쓰면 리스트에서 어떤 조건에 해당하는 녀석들을 끄집어 낸다던지 하는 작업을 편하게 할 수 있습니다.
본 예제는 C#책에 있는 예제를 그대로 사용하였습니다.
예시
키가 175 이상인 친구들을 가려내는 프로그램
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}
};
List<Profile> profiles = new List<Profile>();
foreach(Profile profile in arrProfile)
{
if(profile.Height < 175)
{
profiles.Add(profile);
}
}
//키의 오름차순으로 정렬
profiles.Sort(
(profile1, profile2) =>
{
return profile1.Height - profile2.Height;
});
foreach (var profile in profiles)
{
Console.WriteLine("{0}, {1}", profile.Name, profile.Height);
}
결과
LinQ를 쓰면 코드를 더 간단하게 만들 수 있음
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}
};
//LinQ 구문
var profiles = from profile in arrProfile
where profile.Height < 175
orderby profile.Height
select profile;
foreach(var profile in profiles)
{
Console.WriteLine("{0},{1}", profile.Name, profile.Height);
}
LinQ 사용법
from
- 모든 쿼리식은 반드시 from절로 시작함
- 원본과 원본안에 들어가있는 요소 데이터를 변수로 지정
- foreach의 괄호안에 들어가는 것과 비슷함(범위변수가 차이, foreach는 변수에 데이터를 저장 x, LINQ의 범위변수에는 저장 )
- [[IEnumerable]] 객체만 사용 가능 (변수 할당 시에)
where
- 필터 역할
- 조건에 부합하는 데이터만 선별함
orderby
- 데이터의 정렬을 수행하는 연산자
- 데이터베이스처럼 ASEC 가 있음 - > ascending 물론 반대는 decending
select
- 최종 결과를 추출하는 쿼리식의 마침표 같은 존재
- [[IEnumerable]]의 T는 select 문에 의해서 결정됨
- 무명형식도 가능
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}
};
var profiles = from profile in arrProfile
where profile.Height < 175
orderby profile.Height
select new { Name = profile.Name, InchHeight = profile.Height * 0.393};
foreach (var profile in profiles)
{
Console.WriteLine("{0},{1}", profile.Name, profile.InchHeight);
}
여러 개의 데이터 원본에 질의하기
- 그 as 해서 다시 가공하는 느낌임
- 처음 가공된 정보를 가지고 한번더 가공함
class MainApp { static void Main(string[] args) { Class[] arrClasses = { new Class(){name = "연두반", score = new int[]{ 99,80,70,24} }, new Class(){name = "분홍반", score = new int[]{ 60,45,87,72} }, new Class(){name = "파랑반", score = new int[]{ 92,30,85,94} }, new Class(){name = "노랑반", score = new int[]{ 90,88,0,17} } }; var classes = from c in arrClasses from s in c.score where s < 60 orderby s select new { c.name, Lowest = s }; foreach(var c in classes) { Console.WriteLine($"낙제 : {c.name} ({c.Lowest})"); } } }
group by
- 데이터를 분류하는 문구
- 분류기준으로 데이터를 분류
- Key로 그룹을 나눈 기준의 값을 찾아옴
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}
};
var listProfile = from profile in arrProfile
group profile by profile.Height < 175 into g
select new { GroupKey = g.Key, Profiles = g };
foreach(var Group in listProfile)
{
Console.WriteLine($"- 175 미만? : {Group.GroupKey}");
foreach(var profile in Group.Profiles)
{
Console.WriteLine($">>> {profile.Name}, {profile.Height}");
}
}
Join
- 두개의 데이터 원본을 연결하는 연산
- 특정 필드의 값을 비교하여 일치하는 데이터끼리 연결을 수행
- 내부조인과 외부조인이 있음
- 내부조인은 하나를 기준으로 두개의 테이블을 합치는 개념이고, 외부조인은 기본적으로 내부조인과 비슷하지만 조인 결과에 기준이 되는 데이터 원본이 모두 포함된다는 점이 다름
class MainApp
{
class Profile
{
public string Name { get; set; }
public int Height { get; set; }
}
class Product
{
public string Title { get; set; }
public string Star { get; set; }
}
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}");
}
}
}
Linq의 함수형 출력
- Linq는 사실 쿼리처럼 보이지만 컴파일러 단에서 함수로 바꾸어서 컴파일함
- 아래가 그 예시임
- 53개의 표준 LinQ 연산 메소드 중에 C#의 쿼리식에서 지원하는 것은 11개 뿐임
- 물론 11개로 대부분의 데이터 처리가 가능하지만, 나머지 42개를 모두 활용할 수 있다면 삶이 좀더 편해짐
var profiles = arrProfile.Where(profile => profile.Height < 175)
.OrderBy(profile => profile.Height)
.Select(profile => new
{
Name = profile.Name, InchHeight = profile.Height * 0.393
});
Console.WriteLine("");
Console.WriteLine("--- Linq 함수형 출력 ---");
foreach (var profile in listProfile)
{
Console.WriteLine($"이름{profile.Name}, 작품{profile.Work}, 키{profile.Height}");
}
근데 쿼리식만 적으면 함수들을 못씀 그래서 섞어서 씀
var profiles = from profile in arrProfile
where profile.Height < 180
select profile;
double Average = profiles.Average(profile => profile.Height);
Console.WriteLine(Average);
댓글 남기기