PROGRAMMING WORKSHOP

.Net FrameWork,VB.Net |

LINQ| Let

언어에는 변수가 필수적인데 LINQ문중에 변수를 사용할일은 없나?
예를 들어서 1,2,3,,10까지 숫자가 있다
이것을 하나씩 Random값으로 곱하여 짝수가 될때의 값을 골라내자
라고 한다면..

 Dim oQ = From Q In Enumerable.Range(1, 10)
                Let temp = Q * oRandom.Next(1, 10)
                Where temp Mod 2 = 0
                Select Q, temp

Let temp 는 temp라는 임시변수에 순환된 Q값에 Random값을 곱한값을
임시 보관하는 역할이다
이것을 Where 조건절에서 temp(임시변수)가 짝수일때만 골라라..
하는 것이 될 것이고
이렇게 된 값에서 당초의 Q값과 temp 값두개를 가져오게 한다
이때 두개의 값을 가져 오면, 어떻게 읽지???
이것은 New With{.속성,.속성} 으로 익명의 개체를 만든것과 같은 효과를
해준다...
그래서..



알아서 참! 잘해준다
하다보면, 변수를 여러개 사용하고 싶기도 할것이다
본래의 값을 조건에 맞게 이렇게 저렇게 재가공한 여러개의 값을 만들고 싶을때도 있는것

 Dim oQ = From Q In Enumerable.Range(1, 10)
                Let temp = Q * oRandom.Next(1, 10)
                Let temp1 = Q / 2
                Let temp2 = Q & "_X"
                Where (temp Mod 2 = 0)
                Select Q, temp, temp1, temp2

고것참...잘 만든 언어다

LINQ| Group,By,Into

또 흥미로운 것이 있다
엑셀에서 부분합(SubTotal),피벗테이블(Pivot Table)이라는 것을 종종하였을 것이다
정보가 있으면 어떤 조건에 따라서 그룹핑을 하는 것은 정보분석의 핵심이다
품명이 A,B,C인것을 한달간 판매를 했다면
A라는 것을 따로 분석을 해야 할 것이고
B라고 하는 품명도 해야 할 것이다
어떤 종류별(By) 로 그룹핑(Grouping)을 하고 이것을 이름을
임시 변수 무엇으로 붙여서(Into) 결과를 얻어온다
그런 작업을 위하여 Group,By,Into라는 키워드를 챙기면 된다

예를 들어서
1에서 부터 100까지의 숫자에서
3으로 나누어서 딱떨어지는 값
즉 3으로 나누어서 남는 값이 0인 것
그리고
3으로 나누어서 1이 남는값
그리고
3으로 나누어서 2가 남는값, 이렇게 3개의 그룹으로 나누어서
구분하고 싶다면..
만약 VBA로 한다면 아래와 같이 할 것이다

Sub classicwayInsteadOfLINQ()
' 배열을 3개를 만들던가, 여기에서는 집합체를 3개 만들자
Dim oA As New Collection
Dim oB As New Collection
Dim oC As New Collection
Dim iX As Integer
Dim varX As Variant
Dim sX As String

For iX = 1 To 100
    Select Case iX Mod 3
        Case 0: oA.Add iX
        Case 1: oB.Add iX
        Case 2: oC.Add iX
    End Select
Next
sX = "그룹:3으로 나눠지는 그룹" & String(10, "*") & vbNewLine
For Each varX In oA
    sX = sX & varX & ","
Next
sX = sX & vbNewLine & "그룹:3으로 나누고 1이 남는 그룹" & String(10, "*") & vbNewLine
For Each varX In oB
    sX = sX & varX & ","
Next
sX = sX & vbNewLine & "그룹:3으로 나누고 2가 남는 그룹" & String(10, "*") & vbNewLine
For Each varX In oC
    sX = sX & varX & ","
Next
MsgBox sX

End Sub

아주 번거롭다
하지만 LINQ로 하면 아래와 같다

'Enumerable.Range(1,100)은 VBA에서 1에서 100까지 순환하는 것과 같은 효과!!
 Dim oGroup = From Q In Enumerable.Range(1, 100)
                           Group Q By iP = Q Mod 3 Into myGroup = Group
                           Order By iP
                           Select iP, myGroup


Dim sX As String = ""
For Each x In oGroup
	sX &= vbNewLine & "그룹 : " & _
		Choose(x.iP + 1, "3으로 나눠지는 그룹", "3으로 나누고 1이 남는 그룹", "3으로 나누고 2가 남는 그룹") & _
		New String("*", 10) & vbNewLine
	For Each y In x.myGroup
		sX &= y & ","
	Next
Next
MsgBox(sX)


메시지박스에 나타나는 문자열 정보는 두개가 똑같은 결과이다



어떤 방법으로 해도 되겠지만,
.Net FrameWork의 특성을 응용활용하는 VB.Net을 한다고 하는 것은
새로운 방법에 자꾸 도전하는 것,훨씬 간단하고, 하면 할수록
참으로 생각을 많이 한 방법이로구나!!를 느낄 것이다

이제 분류방식대로 그룹핑을 하였다면
부분합이라는 것도 필요하게 될 것이다
위에서 3으로 나누어지는 값만 그룹핑을 지었다면,
이 그룹의 합계는 얼마고, 갯수는 몇개가 될까??
라는 생각을 하지 않을수 없다
위에서 Let이라는 키워드를 사용하여 변수를 만들었었다
변수를 활용하여..

        Dim oGroup = From Q In Enumerable.Range(1, 100)
                          Group Q By iP = Q Mod 3 Into myGroup = Group
                          Order By iP
                          Let mySum = myGroup.Sum
                          Let myCount = myGroup.Count
                          Select iP, myGroup, mySum, myCount


        Dim sX As String = ""
        For Each x In oGroup
            sX &= vbNewLine & "그룹 : " & _
                Choose(x.iP + 1, "3으로 나눠지는 그룹", "3으로 나누고 1이 남는 그룹", "3으로 나누고 2가 남는 그룹") & " 합계는=" & x.mySum & " 갯수는=" & x.myCount & _
                New String("*", 10) & vbNewLine
            For Each y In x.myGroup
                sX &= y & ","
            Next
        Next

Sum, Count등은 엑셀에서 부분합을 하거나, 피벗테이블에서
사용하던 함수나 마찬가지다, 부분합의 기능이 있는 곳에서는 항상 사용하는
몇개의 함수들 중에서 하나다
물론 위에서 Sum, Count는 개체가 갖고 있는 메소드 인것이고..

실은 위에서 Let을 사용하지 않고 아래와 같이 해도 된다

    Dim oGroup = From Q In Enumerable.Range(1, 100)
                         Group Q By iP = Q Mod 3 Into myGroup = Group
                         Order By iP
                         Select iP, myGroup, mySum = myGroup.Sum, myCount = myGroup.Count

아참..그러고 보니까, 그룹핑하지 않았을때 합계를 내거나, 하는 것을 잊어 먹었다
아래와 같이 할수 있을 것이다

        Dim oQ = (From Q In Enumerable.Range(1, 100)
                Select Q).Sum

        MsgBox("1에서 100까지 합치면 " & oQ)

위와 같이 LINQ문에 괄호치고
Sum이라는 메소드를 붙이고 oQ에서 받으면 oQ는 집합체가 아니고 단일값
그렇다면 집합체로 그냥 받아서 집합체에서 계산해도 되고
아래와 같이

        Dim oQ = From Q In Enumerable.Range(1, 100)
                Select Q

        MsgBox("1에서 100까지 합치면 " & oQ.Sum & vbNewLine & _
               "1에서 100까지 평균" & oQ.Average & vbNewLine & _
               "1에서 100까지 최대값은 " & oQ.Max)

엑셀만 똑똑한줄 알았는데
LINQ도 엄청 똑똑하다
엑셀은 화일이 무겁다, 엑셀의 다양한 계산엔진을 활용하려면
묵직한 엑셀화일이 로딩되어야 한다
하지만 LINQ는 메모리상에서 그냥 처리하는 것이니
잘 활용하면 정보분석에서 대단한 도구를 챙기는 것이다

***[LOG-IN]***