PROGRAMMING WORKSHOP

.Net FrameWork,VB.Net |

LINQ| FROM,IN,WHERE,SELECT

LINQ의 키워드를 하나씩 살펴보자
IEnumerable이나 IEnumerable(Of T) 두개의 Interface를 지원하는 모든 집합체는
LINQ로 처리할수 있다, 모든 집합체라고 보시면 된다
거의 모든 집합체에서 위의 두개의 Interface를 사용하니까..
나중에 Class모듈을 소개할때 Interface를 이야기 할때 자세히 이야기 하기로 하고

집합체중의 기본인 배열도 역시 마찬가지다
예를 들어 아래의 그림과 같이 하면
배열이라는 집합체의 요소값중 짝수만 골라내고 싶다면, 아래와 같이 한다



하나는 LINQ문으로 처리한 것이고
다른 하나는 눈에 익숙한 전통적인 순환방식이다
두개의 그림을 가만히 보면 별것도 아닐것이다
하지만 보이지 않는 .NetFrameWork 엔진에서 처리하는 것은 파워풀한 것
LINQ를 우리가 하는 말로 하나,하나 풀어 보자

From Q In iX

라는 말은 iX라는 집합체에서 각각의 집합체의 요소 Q를

Where Q Mod 2=0

즉 WHERE절은 조건절이다, 전통적 방식의 논리값을 얻는 논리식이 들어가면 된다
다시 Q가 짝수이면...

Select Q

즉 짝수인 것만 골라내어..
변수 oQ에 아래와 같이 몰아 넣어주는 것
Dim oQ= FROM Q....

조건절을 없애고 아래와 같이 한다면

        Dim oQ = From Q In iX
                 Select Q

당연히 원래의 배열과 같은 아무 의미도 없는 짓..
중요한 것은 어떤 조건을 주느냐는 조건절이 Where 절인것
기본적인 키워드를 챙긴것이다
참 간단하네..
From, In, Where,Select

엑셀에서 휠터링은 기본이다

LINQ| Order By,Descending,Ascending

휠터링은 조건이 주어진다는 것은 이미 다 알고 있고
그러니 Where 절은 조건을 주는 절이로구나..
Where절이 없다면 ,조건이 없으니 모두 휠터되는 것
휠터없이 많은 정보를 처리하는 것중에는 엑셀을 생각해 보시면
흠..정렬이 있겠군..
맞다 정렬이다..

	Dim iX() As Integer = {3, 1, 5, 4, 10, 7, 9, 8, 2, 6}

        Dim oQ = From Q In iX
                 Select Q
                 Order By Q Descending

        oQ.ToList.ForEach(Sub(x) MsgBox("내림차" & vbNewLine & x))

        Dim oZ = From Q In iX
                Select Q
                Order By Q Ascending

        oZ.ToList.ForEach(Sub(x) MsgBox("오름차" & vbNewLine & x))

이것을 Where절과 Order By절을 혼합하여 즉 휠터후 정렬을 한다면

	Dim iX() As Integer = {3, 1, 5, 4, 10, 7, 9, 8, 2, 6}

        Dim oQ = From Q In iX
                 Where Q Mod 2 = 0
                 Select Q
                 Order By Q Descending

        oQ.ToList.ForEach(Sub(x) MsgBox("내림차" & vbNewLine & x))

        Dim oZ = From Q In iX
                 Where Q Mod 2 = 0
                Select Q
                Order By Q Ascending

        oZ.ToList.ForEach(Sub(x) MsgBox("오름차" & vbNewLine & x))

별것 아니면서 쉬어질 것이다
일일이 순환하면서 순환문내에서 조건을 주고 걸려내어 다른 집합체에
담고, 그런 법석을 떨지 않아도 되니까, 좋은 도구가 확실하고
다양한 이야기가 전개 되게 된다
단순한 배열만이 아니다 , 시스템에서 제공하는 집합체들도 아래와 같이 할수 있다
예를 들면 System.IO.DirectoryInfo("원하는 폴더").GetFiles() 로 하면 해당 폴더내의
화일개체가 집합체로 얻어진다
그러니 아래와 같이 한다면

 Dim fileList = From file In New System.IO.DirectoryInfo(My.Computer.FileSystem.SpecialDirectories.MyDocuments).GetFiles() _
                       Where file.Name.IndexOf(".xls") > 0 Or file.Name.IndexOf(".csv") > 0
                       Order By file.Name

Dim sFiles As String = ""

fileList.ToList.ForEach(Sub(x) sFiles &= x.Name & vbNewLine)
TextBox1.Text = sFiles

조건절 Where 에서
file개체의 Name속성은 화일의 이름, 이것을 IndexOf(".xls")>0 혹은(or) IndextOf(".csv")>0 라고 한다면
즉, 엑셀화일이나 CSV화일만 휠터링하라는 것이고..
Order By file.Name은 화일명으로 정렬하여 다시 집합체로 얻어내게 되는 것

실은 Dim fileList=From file in.....은
Dim fileList As IEnumerable(Of System.IO.FileInfo)=From file in ....
을 생략한 것이다
위에서 Select file 은 생략해도 된다
만약 위의 내용을 LINQ를 사용하지 않는다면 아래와 같이 하겠지

Dim oFileList As IEnumerable(Of System.IO.FileInfo) = New System.IO.DirectoryInfo(My.Computer.FileSystem.SpecialDirectories.MyDocuments).GetFiles
Dim sFiles As String = ""
For Each ofile As System.IO.FileInfo In oFileList
	If ofile.Name.IndexOf(".xls") > 0 Or ofile.Name.IndexOf(".csv") > 0 Then
		sFiles &= ofile.Name & vbNewLine
	End If
Next
TextBox1.Text = sFiles

그러니 사용하던 방식으로 작업을 해도 된다
하지만 .NetFrameWork의 자원을 최대한 활용하고 좀더 간편한
코딩을 즐기고 싶다면 LINQ를 하면 좋은 것

인터넷의 즐겨찾기를 수시로 지정한다
이 즐겨찾기 목록을 찾아 볼수 있을까
이것도 하나의 집합체이므로 LINQ로 아래와 같이 처리한다

Dim sFiles As String = ""
Dim sPath As String = Environment.GetFolderPath(Environment.SpecialFolder.Favorites)
Dim oPages = From file In New System.IO.DirectoryInfo(sPath).GetFiles()
			 Select file
			 Order By file.Name Ascending

oPages.ToList.ForEach(Sub(x) sFiles &= x.Name & vbNewLine)
TextBox1.Text = sFiles

***[LOG-IN]***

LINQ| Take,Skip Take While, Skip While

싱거운 숫자배열을 버리고, 좀 복잡한 정보를 만들어서 해보자
A_2343 와 같은 문자열 정보를 1000개를 라벨콘트롤의 Text속성으로 주고
실행하여 버튼을 크릭하면 이 정보를 A_2343의 숫자가 500이하인 것만 골라서
오름차 정렬을 하고 그중에서 첫째 10개만 뽑아내기
LINQ가 아닌 방식으로 하려면..좀 번거로울 것이다
한번 해보시고..LINQ로 아래와 같이 처리하면 ,아하 편리하네..하실 것이다

Dim oQ = From Z As String In Me.Label1.Text.Split(vbNewLine)
                Where Z.Trim <> "" AndAlso CInt(Z.Trim.Split("_")(1)) < 500
                Order By Z.Trim.Split("_")(1)
                Take 10


oQ.ToList.ForEach(Sub(x) Me.Label2.Text &= x)

위의 조건절(Where)의 논리식에서 AndAlso라고 하는 것이 보인다
이것이 뭐지?? VB의 편리한 논리연산자중의 하나다
만약 VBA나 오래된 VB에서 한다면 And를 사용하고 그러면 위의 논리식에서는
에러가 난다
만약 VBA에서 한다면 아래와 같이 작성해야 할 것이다

   If Trim(Z)<>"" Then
      If CInt(Split(Trim(Z),"_)(0)< 500 Then
         Do Something
      End If
   End If

If [논리식A] And [논리식B] Then 에서는
[논리식A]와 [논리식B]가 동시에 계산된다,
그리고 두개의 결과값이 True,True일때 True가
되는 것..하나라도 에러가 나면 전체식이 에러가 난다..
위의 경우 Split함수로 배열화시킬수 없는 문자열정보를
두번째논리식에서 시도하려고
하면 에러가 나버려서 전체 표현식이 에러가 되어 버리는 것

하지만 AndAlso는 차례대로 계산한다
[논리식A]가 False이면 두번째 [논리식B]는 계산하지 않고 전체가 False로 끝난다
그래서 [논리식B]를 계산하지 않으니,에러가 날일이 없다

위에서 새로운 LINQ 키워드는 Take라는 단어
말그대로 Take 10, 결과물 집합체의 처음 5개만 택하라!!
라는 의미..
그리고,,아하..
Order By Z.Trim.Split("_")(1)
집합체,순환요소의 값을 토막을 내어서 정렬도 하는구나?
즉 문자와 숫자가 _로 연결된 것을 배열화하여 숫자만으로 정렬을 한다는 것
얼마나 편리한가..

Select 절은 입력하지 않아도 Default로 입력된 것으로 인식하니
넣어도 되고, 않넣어도 된다
만약 집합체 각각의 요소를 다시 어떤 계산을 한
결과를 얻고 싶은 특별한 경우에는 명시적으로 표현하고...
Select 절에
Select z & "_A"
같이 하면 모든 요소값에 _A가 붙게 된다

아무튼 LINQ는 어떻게 하면 말하듯이 한줄에 많은 일을 시킬까
연구한 도구인 셈이다

Take와 마찬가지로 Skip이라는 키워드가 있다 Skip 10이라고 하면 앞에서 10개를 제외하고 나머지를 가져오라!!
인 것이고

Take While이라는 조건절도 있다
이것은 조건이 맞는 값을 처음에 만나면 계속 조건이 맞는 값일때까지
가져오고 나머지는 생략한다



Skip While은 반대로
앞에서 조건이 안맞는 것을 만나는 순간, 그이후의 값을 모두 가져 온다

***[LOG-IN]***