본문 바로가기

카테고리 없음

LINQ(Language-INtegrated Query)

LINQ는 데이터 질의(Query) 기능을 C#에서 사용할 수 있는 기술이다.

 

쉽게 설명하자면 C#의 배열, 컬렉션, XML, DataSet 등 내가 원하는 데이터만 가져오고 싶은 경우 사용할 수 있는 기술이라고 말할 수 있다.

 

분기문을 사용하지 않고도 원하는 데이터를 한번에 출력할 수 있다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace LINQ
{
    class Program
    {
        static void Main(string[] args)
        {
            string[] strArr = { "Apple", "Banana", "Car", "Angular", "Add", "Sum" };
            var linqResult = from str in strArr
                             where str.StartsWith("A") && str.Length > 3
                             select str;
            foreach(var str in linqResult)
                Console.Write(str + " ");
        }
    }
}

[] <- 인덱서 인덱서를 사용하면 배열데이터를 무한대로 가져올 수 있다.

 

LINQ 에서는 foreach 를 무조건 쓴다.


LINQ의 장점

- SQL과 유사하므로 SQL사용이 익숙하다면 쉽게 접근할 수 있다.

- LINQ는 컴파일 시간에 타입을 체크합니다. 따라서, 프로그램 실행 전에 문제가 되는 코드를 수정할 수 있다.

- 반복문, 조건문을 사용하는 것보다 코드가 단순해 진다.

- LINQ 질의는 재사용할 수 있다.

SINQ의 단점

- RDBMS를 사용해 보지 않은 개발자에게는 어려울 수 있다.

- SQL과 유사하지만 복잡한 질의는 작성할 수 없다.

- 질의가 잘못된 경우 for, foreach와 같은 반복문을 사용하는 것보다 성능이 저하될 수 있다.

 

LINQ의 기본 구조

from - 어떤 데이터에서 원하는 값을 추출할 것인지

where - 원하는 값을 추출하기 위한 조건

select - 데이터에서 어떤 항몰을 추출할 것인지

order by - 어떤 항목을 기준으로 정렬할 것인지

 

 

using System;
using System.Collections.Generic;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace LINQ
{
    class Person
    {
        public string name;
        public int age;
    }
    class Program
    {
        static void Main(string[] args)
        {
            List<Person> person = new List<Person>
            {
                new Person() { name = "Bob", age = 20 },
                new Person() { name = "Nick", age = 34 },
                new Person() { name = "John", age = 30 }
            };

            var linqResult = from obj in person 
                             where obj.age >= 30 
                             select obj.name;

            foreach (var name in linqResult)
                Console.Write(name + " ");

        }
    }
}

 

SQL 과 마찬가지로 order by는 오름차순으로 되어있습니다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace LINQ
{
    public class Student
    {
        public string name { get; set; }
        public int score { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>
            {
                new Student{name = "zzz", score = 88},
                new Student{name = "kim", score = 50},
                new Student{name = "han", score = 76},
                new Student{name = "park", score = 45},
                new Student{name = "peter", score = 84},
                new Student{name = "lee", score = 98}
            };
            var smart = from student in students
                        where student.score >= 60   //60점 이상만
                        orderby student.name ascending  //이름순으로 정렬
                        select student.name;    //이름만 추출
            foreach (string studentName in smart)    //결과 출력
                Console.WriteLine(studentName);
        }
    }
}

 

합 Sum 최대값 Max 최소값 Min 평균값 Average 데이터 갯수 Count 를  사용한 예제 코드 입니다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace LINQ
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            Console.WriteLine("sum: " + numbers.Sum());
            Console.WriteLine("max: " + numbers.Max());
            Console.WriteLine("min: " + numbers.Min());
            Console.WriteLine("average: " + numbers.Average());
            Console.WriteLine("count: " + numbers.Count());
        }
    }
}

 

Aggregate는 사용자가 직접 해당 데이터들을 어떻게 가공할지 명시 할 수 있습니다.

인자들의 합이나 최대값을 구하는 것이 아닌 가장 큰 수와 가장 작은 수의 합이라던지 모든 수의 곱셈이라던지 등에 다양한 방식에 집계를 사용자가 직접 작성할 수 있는 장점이 있습니다.

 

람다식을 사용하여 함수의 내용을 쉽게 넘겨줄 수 있습니다.

모든 인자들의 곱을 계산하는 예제입니다.

 

모든 인자들의 곱을 계산하는 예제입니다. 첫번째 인자와 두번째인자를 곱해서 다시 첫번째 인자에 놓고 다시 그 다음 번째 인자를 두번째 인자로 놓고 곱하는것을 반복합니다.

        static void Main(string[] args)
        {
            int[] numbers = { 1, 2, 3, 4, 5 };
            var data = numbers.Aggregate((num1, num2) => num1 * num2);
            Console.WriteLine(data);
        }

결과는 1*2*3*4*5 = 120 입니다.

 

위와 같은 예제 Aggregate 함수에 파라미터를 앞에 하나 추가하였습니다.

첫번째 인자 하나는 고정하는 기능을 합니다.

100*1*2*3*4*5의 결과가 출력되게 됩니다. 해당 기능은 대소 비교를 할 때 가장 처음에 기준값을 정할 때에도 사용이 가능합니다. 

 static void Main(string[] args)
        {
            int[] numbers = { 1, 2, 3, 4, 5 };
            var data = numbers.Aggregate(100, (num1, num2) => num1 * num2);
            Console.WriteLine(data);
        }

이처럼 고정값을 가진 다른 문법이 있었습니다. 바로 Enum 입니다. Enum은 0이 초기값이고, 기준값을 정해주면 1씩 증가 하는 상수였죠.

이와 유사하게 파라미터 100을 하나 추가함으로서 기준값이 100에 연산을 추가적으로 수행합니다.

 

   static void Main(string[] args)
        {
            String[] names = { "abc", "kim", "lee", "han", "park" };
            var data = names.Aggregate((str1, str2) => str1 + ", " + str2);
            Console.WriteLine(data);
        }

출력: abc, kim, lee, han, park

이런식으로 데이터를 출력하면 데이터를 구분하는 토큰을 쉽게 넣을 수가 있습니다. 이렇게 완성된 출력값에서는 ", "가 토큰이 됩니다.

 

 

학생들의 이름과 점수를 담고있는 객체들을 List로 가지고 있는 데이터에서 학생들의 평균점수를 구하는 예제입니다. 클래스를 사용하여 학생의 이름과 점수를 저장할 수 있도록 하였습니다. 그리고 LINQ를 사용하여 데이터를 가공하는 것을 볼 수 있습니다.

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace LINQ
{
    public class Student
    {
        public string name { get; set; }
        public int score { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>
            {
                new Student{name = "zzz", score = 88},
                new Student{name = "kim", score = 50},
                new Student{name = "han", score = 76},
                new Student{name = "park", score = 45},
                new Student{name = "peter", score = 84},
                new Student{name = "lee", score = 98}
            };
            var result = (from student in students select student).Average(student => student.score);
            Console.WriteLine("전체 학생의 평균: " + result);
        }
    }
}

 

 

학생들의 이름이 4글자 이상인 학생들만 추출하고 그 학생들의 점수의 합을 구하는 예제입니다.

from으로 학생 하나씩 선택하여 where로 이름이 4글자인 학생만 추출하고select함수로 학생의 정보를 받습니다. 그리고 Sum함수로 이름이4글자인 학생의 점수들을 모두 합칩니다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace LINQ
{
    public class Student
    {
        public string name { get; set; }
        public int score { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>
            {
                new Student{name = "zzz", score = 88},
                new Student{name = "kim", score = 50},
                new Student{name = "han", score = 76},
                new Student{name = "park", score = 45},
                new Student{name = "peter", score = 84},
                new Student{name = "lee", score = 98}
            };
            var result = (from student in students 
                          where student.name.Length >= 4 
                          select student).Sum(student=>student.score);
            Console.WriteLine("이름이 4글자 이상인 학생들의 점수 합: " + result);
        }
    }
}

 

group by 키워드를 사용하여 50점 이상 학생과 미만 학생으로 나눈 후 해당 학생들의 숫자와 평균, 최대값을 구하는 코드이다.

group by 는 특정 조건으로 데이터들을 그룹을 지어 주는 기능을 한다.

에를 들어 1~100까지의 수가 있어서 group by 를 사용하여 50 이상과 미만으로 나누어 각각의 평균을 구할 수 있다.

자주 사용되기 때문에 알아 두면 좋다.

그룹으로 나눈 각각의 그룹은 into 키워드를 사용하여 g로 나타낸다.

그래서 h.key 를 사용하여 참인지 거짓인지를 가지고 어느 그룹의 데이터 인지 알수 있다.

따라서 각 그룹의 평균과 최대값 등을 알아 낼 수 있다.

검색 범위를 지정해 줄 수 있는 기능이기 때문에 프로그램 성능과도 직결된다.

많이 사용하고 중요하다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace LINQ
{
    public class Student
    {
        public string name { get; set; }
        public int score { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            List<Student> students = new List<Student>
            {
                new Student{name = "zzz", score = 88},
                new Student{name = "kim", score = 50},
                new Student{name = "han", score = 76},
                new Student{name = "park", score = 45},
                new Student{name = "peter", score = 84},
                new Student{name = "lee", score = 98}
            };
            var result = from student in students
                         group student by student.score >= 50 into g   //50점을 기준으로 나열한다.
                         select new
                         {
                             key = g.Key == true ? "50점 이상" : "50점 미만", //50점 이상 데이터인지 확인
                             count = g.Count(), //해당 구간의 학생 수
                             avr = g.Average(student => student.score),    //해당 구간의 평균
                             max = g.Max(student => student.score)    //해당 구간의 최대값
                         };
            foreach(var data in result)
            {
                Console.WriteLine(data.key + "학생 수: " + data.count);
                Console.WriteLine(data.key + "중 최대 점수 : " + data.max);
                Console.WriteLine(data.key + "학생들의 평균: " + data.avr);
                Console.WriteLine("---------------------------------------");
            }
        }
    }
}