목록

LINQ란

unity unirx관련 자료 보다가.. linq까지 왔다.

linq이용 하면 데이터 정렬하는데 있어 편하다고 해서 함 알아보자.


LINQ 뭣 인가.

질의로 통한된 언어 -> 데이터에 대해 질문하는 언어

  • LINQ 문을 이용하면 가장 일반적으로 정렬, 검색 및 필터링을 손쉽게 할 수 있다.
  • 쿼리란??

    • 데이터 소스에서 데이터를 검색하는 식이다. 관계형 데이터베이스에서 주로 사용.
  • LINQ to XML, LINQ to SQL, LINQ to Obejct 등이 있는데 우리가 쓸 건 LINQ to Object

퍼포먼스는 ??

물론 생으로 짠 코딩 보단 여러개 돌려봤을 떄 느리지만,

update()처럼 매 프레임 마다 실행하는 곳에 쓰지 않는다면, 크게 문제될건 없다.

이러한걸 커버할 만큼 매력적이다.

LINQ문은 약간의 가비지를 생성하므로 매 프레임마다 호출하는 함수에 넣지 말도록 주의.


기본적인 LINQ

LINQ 쿼리 수행을 위해 반드시 포함해야 하는 네임스페이스

using System.Linq;

person 을 담고 있는 people 즉, List<person> 이 있다고 가정해보자,

var all = from person in people
          select person;

foreach(var item in all)
{
  console.WriteLine(item);
}

위 구문 실행시 person 정보가 출력이 될 텐데 from으로 해당 범위 정하고 in으로 어떤걸 탐색할지, select으로 누굴 뽑을지 정한다.

foreach와의 대응 관계를 보면 대략 이렇다.

frome person in peope -----------> foreach(var person in people)

select person; ------------------> yield return person;

yield return이 IEnumerable를 반환 하므로 select 또한 IEnumerable 반환을 유추 할 수 있다.

사실 LINQ는 컴파일러에 의해 빌드 시 원래 사용하는 확장메서드 코드로 변경되 컴파일 되기 떄문에 아래와 같이 전부 동일한 코드.

LINQ 표현         /       from person in people
                          select person;

확장 메서드 표현   /       people.Select((elem) => elem);

일반 메서드 표현   /       IEnumerable<Person> SelectFunc(List<Person> people)
                          {
                            foreach(var item in people)
                            {
                              yield return item;
                            }
                          }

반확시 IEnumerable로 어느것이든 형변환이가능하므로 꼭 person만 반환하는게 아니라

person.name, new { name = person.name, ...} 등으로 변환 시킬 수 있다는점이 유용하게 쓰인다.


LINQ 구문

  • WHERE 특정 조건을 만족하는 데이털르 필터링할 떄 사용한다.

    var endWhithS = from person in people
                  where person.Name.EndsWith("s")
                  select person;
  • ORDERBY LINQ에서 정렬 작업을 수행할 떄 사용된다.

    orderby는 뒤이어 나오는 값을 기준으로 기본값으로 ascending 이 지정된 오름차순 정렬 이지만 descending 으로 지정해 내림차순으로 바꿀 수 있다.

    var ageSortDesc = from person in people
                    orderby person.Age descending
                    select person;
  • GROUP BY 컬렉션의 항목을 그룹핑할 떄 사용된다. 특이한 점이라면 select 구문이 올 수 없다는 점.

    왜냐면 group by 기능이 select을 포함하고 있기 떄문이다. 최종적으로 그룹 컬렉션을 반환한다.

    var addrGroup = person in people
                  group person by pserson.Address;

    이러면 addrGroupAddress 그룹으로 묶인 컬렉션이 반환 된다.

    foreach(var itemGroup in addrGroup)
    {
      // 각 실 아이템 보려면 그룹핑에서 한번 더 찾아야 됨.
      foreach(var item in itemGroup)
      {
      }
    }

    또한, group 반환 by 그룹핑 조건 이므로 반환 부분을 형변환해 작업해도 무관.

    var nameAgeList = from person in people
                    group new { Name = person,Name, Age = person.Age } by person.Address;
  • JOIN 다른 컬렉션과의 상호관계 나타낼 떄 쓰인다.

    JOIN 참조할 데이터 in 참조할 다른 컬렉션 on 조건 equals 조건 형식.

    var nameToLangList = from person in people
                       join language in languages on person.Name equals language.Name
                       select new { Name = person.Name, Age = person.Age, Language = language.Language };
    // languages의 language페ㅗ으의 Name을 person의 Name과 같은 것만 select한다는 의미

    여기서 주목 해야할 부분은 만약 languages에 person.Name과 같은 레코드가 2개 이상 존재한다면,

    select의 결과물로 각각 다른 레코드로 2개가 생성된다.

    —> on ... equals ... 조건을 만족하는 모든 레코드를 찾는다.는 의미 또한,

    —> on ... equals ... 조건을 만족하는 모든 레코드를 찾는다.는 조건을 만족하는 레코드가 없다면 select에 반영되지 않는다.

    이러한 Join유형을 가리켜 내부 조인(Inner Join)이라 부른다.
    반대로 외부조인(Outer jOIN)도 있겠쥬??
    외부조인은 해당 레코드를 누락시키지 않고 포함 시키는걸 의미.

    LINQ에서는 외부조인을 따로 예약어로 만들어 놓지 않았으므로,

    join으로 엮이는 컬렉션을 한번 더 후처리하는 방법을 사용해야한다.

    var nameToLangAllList = from person in people
                          join language in languages on person.Name equals language.Name into lang
                          from language in lang.DefaultIfEmpty(new MainLanguage())
                          select new { Name = person.Name, Age = person.Age, Language = language.Language };
    // 두번 쨰 줄에 join한 languages 내용을 lang이라는 임시 컬렉션에 보낸다.
    // 그리고 개별 요소에 대해 IEnumerable<T> 타입의 DefaultIfEmpty 확장메서드를 호출.
    // 이 메서드는 요소 중 값이 비어 있으면 인자로 전달된 "new MainLanguage()" 값을 사용.
    // 그러면 person name에 해당하지 않아 제외됐던 lang레코드들도 포함되게 된다.

IEnumerable 확장 메서드

LINQ IEnumerable 확장 메서드
Select Select
Where Where
orderby [ascending] OederBy
orderby [descending] OrderByDescending
group … by GroupBy
join … in … on … equals Join
join … in … on … equals … into GroupJoin

물론 확장 메서드가 더 존재.. 필요 시 검색으로 참고


IEnumerable ??

IEnumerable는 배열과 다르게 임의접근이 안되고 오로지 순차(순방향) 접근을 통한다.

또한 기본적인 반복자 기능을 하므로 foreach나 LINQ로 확장해서 사용가능하다.

상황에 따라 IEnumerable을 쓸지 배열을 쓸지 선택하자.

단 주의점은 IEnumerable컬렉션을 배열로 만들어 쓸 수있는데 (.ToArray()메서드 이용) 만들 때

주의할 부분이 IEnumerable같은 경우 yield로 여기에 프로그램을 지연시키는 코드가 들어 갈 수 있으므로

ToArray시 전체 순방하며 만드므로 프로그램 지연코드도 그대로 실행되 생성 시 느려질 수 있다는 점.

  • 배열

    1. 메모리 사용량이 많다.
    2. 속도가 빠르다.
    3. 큰 메모리에 최적화된 값을 설정하려면 시간이 걸릴 수 있다.
  • 열거 인터페이스

    1. 메모리를 덜 사용.
    2. 사용하는 데 시간이 걸린다.

LINQ 쿼리라고 해서 모두 지연 연산, 지연 실행 방식으로 동작하는 것은 아니다.

쿼리 반환 타입이 IEnumerable, IOrderedEnumerable가 아니라면 실행 즉시 실행되어 실행 결과가 반환된다는점!!


참고