Home 14. LINQ 2
Post
Cancel

14. LINQ 2

쿼리

쿼리 식

  • 이 전 내용은 표준 쿼리식과 그 키워드에 관한 내용들.

    Description
    from데이터 소스와 범위 변수(반복 변수와 유사함)를 지정.
    where논리적 AND 및 OR 연산자(&& 또는 ||)로 구분된
    하나 이상의 부울 식을 기준으로
    소스 요소를 필터링.
    select쿼리를 실행할 때 반환된 시퀀스의 요소에
    사용할 형식 및 모양을 지정.
    group지정된 키 값에 따라 쿼리 결과를 그룹화.
    intojoin, group 또는 select 절의 결과에 대한
    참조로 사용할 수 있는 식별자 제공.
    orderby요소 형식에 대한 기본 비교자에 따라
    오름차순 또는 내림차순으로 쿼리 결과를 정렬.
    join지정한 두 일치 조건 간의
    같음 비교를 기반으로 두 데이터 소스를 조인.
    let쿼리 식에 하위 식 결과를 저장할 범위 변수 도입.
    injoin 절의 상황별 키워드.
    onjoin 절의 상황별 키워드.
    equalsjoin 절의 상황별 키워드.
    bygroup 절의 상황별 키워드.
    ascendingorderby 절의 상황별 키워드.
    descendingorderby 절의 상황별 키워드.
  • 이상 내용들은 이 전 내용 또는 없으면 나중에 추가하겠지..

쿼리 연산자

  • LINQ 패턴을 형성하는 메서드.
    • 이 중 대부분은 sequences라는 형식 개체에서 동작
      • IEnumerable<T> 인터페이스
      • IQueryable<T> 인터페이스
      • 위 둘을 구현함.
    • 필터링, 프로젝션, 집계, 정렬 등 다양한 쿼리 기능 제공.
  • 두 가지 LINQ 표준 쿼리 연산자 집합이 있다.
    • IEnumerable<T> 형식의 개체와 작동하는 연산자,
      IQueryable<T> 형식의 개체와 작동하는 연산자
    • 각 집합을 구성하는 메서드는 각각
      Enumerable 및 Queryable 클래스의 정적 멤버.
    • 작동하는 형식의 확장 메서드로 정의.
      확장 메서드는 정적 메서드 구문 또는
      인스턴스 메서드 구문을 사용하여 호출할 수 있다.
    • 아래 method 예시에 이 두 경우 모두 씀
      • AsEnumerable() : 대부분의 경우 기본이
        Enumerable 형이거나 이 키워드는 생략 가능한듯
      • AsQueryable은 꼭 명시 해줘야되는데
        Enumerable이면서 Queryable은안되는 경우가 가끔 있음
  • 몇 가지 표준 쿼리 연산자 메서드는
    IEnumerable<T> 또는 IQueryable<T>
    이외의 형식에서 작동.
    • Enumerable 형식은
      둘 다 IEnumerable 형식의 개체에서 작동하는
      두 가지 메서드를 정의.
    • 이러한 메서드
      Cast<TResult>(IEnumerable) 및
      OfType<TResult>(IEnumerable)을 사용하면
      매개 변수화되지 않거나
      제네릭이 아닌 컬렉션을
      LINQ 패턴에서 쿼리 할 수 있음.
    • 강력한 형식의 개체 컬렉션을 만들어 이를 수행.
    • Queryable 클래스는
      IQueryable 형식의 개체에서 작동하는
      Cast<TResult>(IQueryable) 및
      OfType<TResult>(IQueryable)의
      두 가지 유사한 메서드를 정의.
  • 표준 쿼리 연산자는 반환값에따라 실행되는 타이밍이 다름.
    • 단일 값 또는 시퀀스가 있음.
    • singleton 값(예: Average 및 Sum)을 반환하는 메서드는 즉시 실행.
    • 시퀀스를 반환하는 메서드는 쿼리
      실행을 지연하고 열거 가능한 개체를 반환.
  • IEnumerable<T>을 확장하는 메서드
    • 메모리 내 컬렉션에 대해 작동하는 메서드
    • 반환된 열거 가능한 개체는 메서드에 전달된 인수를 캡처.
    • 해당 개체를 열거하는 경우
      쿼리 연산자의 논리가 사용되며
      쿼리 결과가 반환.
  • IQueryable<T>을 확장하는 메서드
    • 쿼리 동작을 구현하지 않음.
    • 수행할 쿼리를 나타내는 식 트리를 빌드.
    • 쿼리 처리는 IQueryable<T> 개체에 의해 처리.
  • 쿼리 메서드에 대한 호출을 하나의 쿼리로 함께 연결할 수 있으므로
    쿼리가 임의로 복잡해질 수 있다.

  • 식 / 연산자 비교
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    
    string sentence = "the quick brown fox jumps over the lazy dog";  
    // Split the string into individual words to create a collection.  
    string[] words = sentence.Split(' ');  
        
    // Using query expression syntax.  
    var query = 
        from word in words  
        group word.ToUpper() by word.Length into gr  
        orderby gr.Key  
        select new { Length = gr.Key, Words = gr };  
        
    // Using method-based query syntax.  
    var query2 = 
        words.  
        GroupBy(w => w.Length, w => w.ToUpper()).  
        Select(g => new { Length = g.Key, Words = g }).  
        OrderBy(o => o.Length);  
        
    foreach (var obj in query)  
    {  
        Console.WriteLine("Words of length {0}:", obj.Length);  
        foreach (string word in obj.Words)  
            Console.WriteLine(word);  
    }  
        
    // This code example produces the following output:  
    //  
    // Words of length 3:  
    // THE  
    // FOX  
    // THE  
    // DOG  
    // Words of length 4:  
    // OVER  
    // LAZY  
    // Words of length 5:  
    // QUICK  
    // BROWN  
    // JUMPS
    
    
  • 분류
    • Sorting Data
    • Set Operations
    • Filtering Data
    • Quantifier Operations
    • Projection Operations
    • Partitioning Data
    • Join Operations
    • Grouping Data
    • Generation Operations
    • Equality Operations
    • Element Operations
    • Converting Data Types
    • Concatenation Operations
    • Aggregation Operations

Sorting Data(C#)

  • 하나 이상의 특성을 기준으로 시퀀스의 요소를 정렬.
  • 첫 번째 정렬 기준은 요소에 대해 기본 정렬을 수행.
  • 두 번째 정렬 기준을 지정하면 각 기본 정렬 그룹 내의 요소를 정렬.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    OrderBy값을 오름차순으로 정렬.orderbyEnumerable.OrderBy
    Queryable.OrderBy
    OrderByDescending값을 내림차순으로 정렬.orderby … descendingEnumerable.OrderByDescending
    Queryable.OrderByDescending
    ThenBy2차 정렬을 오름차순으로 정렬.orderby …, …Enumerable.ThenBy
    Queryable.ThenBy
    ThenByDescending2차 정렬을 내림차순으로 정렬.orderby …, … descendingEnumerable.ThenByDescending
    Queryable.ThenByDescending
    Reverse컬렉션에서 요소의 순서를 반대로 정렬.해당 사항 없음.Enumerable.Reverse
    Queryable.Reverse
  • OrderBy
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    class Pet
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    
    public static void OrderByEx1()
    {
        Pet[] pets = { new Pet { Name="Barley", Age=8 },
                      new Pet { Name="Boots", Age=4 },
                      new Pet { Name="Whiskers", Age=1 } };
    
        IEnumerable<Pet> query =  
            pets
            .OrderBy(pet => pet.Age);
        IEnumerable<Pet> query =  
            pets
            .AsQueryable()
            .OrderBy(pet => pet.Age);
          
        foreach (Pet pet in query)
        {
            Console.WriteLine("{0} - {1}", pet.Name, pet.Age);
        }
    }
    /*
    This code produces the following output:
    
    Whiskers - 1
    Boots - 4
    Barley - 8
    */
    
  • OrderByDescending
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    
    /// <summary>
    /// This IComparer class sorts by the fractional part of the decimal number.
    /// </summary>
    public class SpecialComparer : IComparer<decimal>
    {
        /// <summary>
        /// Compare two decimal numbers by their fractional parts.
        /// </summary>
        /// <param name="d1">The first decimal to compare.</param>
        /// <param name="d2">The second decimal to compare.</param>
        /// <returns>1 if the first decimal's fractional part
        /// is greater than the second decimal's fractional part,
        /// -1 if the first decimal's fractional
        /// part is less than the second decimal's fractional part,
        /// or the result of calling Decimal.Compare()
        /// if the fractional parts are equal.</returns>
        public int Compare(decimal d1, decimal d2)
        {
            decimal fractional1, fractional2;
    
            // Get the fractional part of the first number.
            try
            {
                fractional1 = decimal.Remainder(d1, decimal.Floor(d1));
            }
            catch (DivideByZeroException)
            {
                fractional1 = d1;
            }
            // Get the fractional part of the second number.
            try
            {
                fractional2 = decimal.Remainder(d2, decimal.Floor(d2));
            }
            catch (DivideByZeroException)
            {
                fractional2 = d2;
            }
    
            if (fractional1 == fractional2)
                return Decimal.Compare(d1, d2);
            else if (fractional1 > fractional2)
                return 1;
            else
                return -1;
        }
    }
    
    public static void OrderByDescendingEx1()
    {
        List<decimal> decimals =
            new List<decimal> { 6.2m, 8.3m, 0.5m, 1.3m, 6.3m, 9.7m };
    
        IEnumerable<decimal> query =
            decimals
            .OrderByDescending(num => num, new SpecialComparer());
        IEnumerable<decimal> query =
            decimals
            .AsQueryable()
            .OrderByDescending(num => num, new SpecialComparer());
        foreach (decimal num in query)
        {
            Console.WriteLine(num);
        }
    }
    
    /*
    This code produces the following output:
    
    9.7
    0.5
    8.3
    6.3
    1.3
    6.2
    */
    
  • ThenBy
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    string[] fruits = { "grape", "passionfruit", "banana", 
                        "mango", "orange", "raspberry", 
                        "apple", "blueberry" };
    
    // Sort the strings first by their length and then
    //alphabetically by passing the identity selector function.
    IEnumerable<string> query = 
        fruits
        .OrderBy(fruit => fruit.Length)
        .ThenBy(fruit => fruit);
    IEnumerable<string> query = 
        fruits
        .AsQueryable()
        .OrderBy(fruit => fruit.Length)
        .ThenBy(fruit => fruit);
    foreach (string fruit in query)
    {
        Console.WriteLine(fruit);
    }
    
    /*
        This code produces the following output:
    
        apple
        grape
        mango
        banana
        orange
        blueberry
        raspberry
        passionfruit
    */
    
  • ThenByDescending
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    
    public class CaseInsensitiveComparer : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            return string.Compare(x, y, true);
        }
    }
    
    public static void ThenByDescendingEx1()
    {
        string[] fruits = { "apPLe", "baNanA", "apple", 
                          "APple", "orange", "BAnana", 
                          "ORANGE", "apPLE" };
    
        // Sort the strings first ascending by their length and
        // then descending using a custom case insensitive comparer.
        IEnumerable<string> query = 
            fruits
            .OrderBy(fruit => fruit.Length)
            .ThenByDescending(fruit => fruit, new CaseInsensitiveComparer());
        IEnumerable<string> query = 
            fruits
            .AsQueryable()
            .OrderBy(fruit => fruit.Length)
            .ThenByDescending(fruit => fruit, new CaseInsensitiveComparer());
        foreach (string fruit in query)
        {
            Console.WriteLine(fruit);
        }
    }
    
    /*
        This code produces the following output:
    
        apPLe
        apple
        APple
        apPLE
        orange
        ORANGE
        baNanA
        BAnana
    */
    
  • Reverse
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    char[] apple = { 'a', 'p', 'p', 'l', 'e' };
    
    char[] reversed = apple.Reverse().ToArray();
    IQueryable<char> reversed = apple.AsQueryable().Reverse();
    
    foreach (char chr in reversed)
    {
        Console.Write(chr + " ");
    }
    Console.WriteLine();
    
    /*
    This code produces the following output:
    
    e l p p a
    */
    

Set Operations

  • 동일 컬렉션이나 별개 컬렉션(또는 집합)에
    동등한 요소가 있는지 여부에 따라
    결과 집합을 생성하는 쿼리 작업.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    Distinct컬렉션에서 중복 값을 제거.해당 사항 없음.Enumerable.Distinct
    Queryable.Distinct
    Except두 번째 컬렉션에 표시되지 않는
    한 컬렉션의 요소를 의미하는
    차집합을 반환.
    해당 사항 없음.Enumerable.Except
    Queryable.Except
    Intersect두 컬렉션에 공통으로 표시되는
    교집합을 반환.
    해당 사항 없음.Enumerable.Intersect
    Queryable.Intersect
    Union두 컬렉션 모두 포함한
    합집합을 반환.
    해당 사항 없음.Enumerable.Union
    Queryable.Union
  • Distinct
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    List<int> ages = new List<int> { 21, 46, 46, 55, 17, 21, 55, 55 };
    
    IEnumerable<int> distinctAges = ages.Distinct();
    IEnumerable<int> distinctAges = ages.AsQueryable().Distinct();
    
    Console.WriteLine("Distinct ages:");
    
    foreach (int age in distinctAges)
    {
        Console.WriteLine(age);
    }
    
    /*
    This code produces the following output:
    
    Distinct ages:
    21
    46
    55
    17
    */
    
  • Except
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    double[] numbers1 = { 2.0, 2.0, 2.1, 2.2, 2.3, 2.3, 2.4, 2.5 };
    double[] numbers2 = { 2.2 };
    
    IEnumerable<double> onlyInFirstSet = 
        numbers1
        .Except(numbers2);
    IEnumerable<double> onlyInFirstSet = 
        numbers1
        .AsQueryable()
        .Except(numbers2);
    foreach (double number in onlyInFirstSet)
        Console.WriteLine(number);
    
    /*
    This code produces the following output:
    
    2
    2.1
    2.3
    2.4
    2.5
    */
    
  • Intersect
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    int[] id1 = { 44, 26, 92, 30, 71, 38 };
    int[] id2 = { 39, 59, 83, 47, 26, 4, 30 };
    
    // Get the numbers that occur in both arrays (id1 and id2).
    IEnumerable<int> both = 
        id1
        .Intersect(id2);
    IEnumerable<int> both = 
        id1
        .AsQueryable()
        .Intersect(id2);
    
    foreach (int id in both)
        Console.WriteLine(id);
    
    /*
        This code produces the following output:
    
        26
        30
    */
    
  • Union
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    int[] ints1 = { 5, 3, 9, 7, 5, 9, 3, 7 };
    int[] ints2 = { 8, 3, 6, 4, 4, 9, 1, 0 };
    
    // Get the set union of the items in the two arrays.
    IEnumerable<int> union = 
        ints1
        .Union(ints2);
    IEnumerable<int> union = 
        ints1
        .AsQueryable()
        .Union(ints2);
    
    foreach (int num in union)
        Console.Write("{0} ", num);
    
    /*
        This code produces the following output:
    
        5 3 9 7 8 6 4 1 0
    */
    

Filtering Data

  • 지정된 조건을 충족하는 요소만 포함하도록 결과 집합을 제한.
  • 필터링은 선택이라고도 한다.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    OfType지정된 형식으로 캐스트할 수 있는지
    여부에 따라 값을 선택.
    해당 사항 없음.Enumerable.OfType
    Queryable.OfType
    Where조건자 함수를 기반으로 하는 값을 선택.whereEnumerable.Where
    Queryable.Where
  • OfType
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    
    IList fruits = new List<object>();
    fruits.Add("Mango");
    fruits.Add("Orange");
    fruits.Add("Apple");
    fruits.Add(3.0);
    fruits.Add("Banana");
    
    // Apply OfType() to the ArrayList.
    IEnumerable<string> query1 = 
        fruits
        .OfType<string>();
    IQueryable<string> query1_1 = 
        fruits
        .AsQueryable()
        .OfType<string>();
    
    Console.WriteLine("Elements of type 'string' are:");
    foreach (string fruit in query1)
    {
        Console.WriteLine(fruit);
    }
    
    // The following query shows that the standard query operators such as
    // Where() can be applied to the ArrayList type after calling OfType().
    IEnumerable<string> query2 =
        fruits
        .OfType<string>()
        .Where(fruit => fruit.ToLower().Contains("n"));
    IEnumerable<string> query2_2 =
        fruits
        .AsQueryable()
        .OfType<string>()
        .Where(fruit => fruit.ToLower().Contains("n"));
    Console.WriteLine("\nThe following strings contain 'n':");
    foreach (string fruit in query2)
    {
        Console.WriteLine(fruit);
    }
    
    // This code produces the following output:
    //
    // Elements of type 'string' are:
    // Mango
    // Orange
    // Apple
    // Banana
    //
    // The following strings contain 'n':
    // Mango
    // Orange
    // Banana
    
  • Where
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    int[] numbers = { 0, 30, 20, 15, 90, 85, 40, 75 };
    
    // Get all the numbers that are less than or equal to
    // the product of their index in the array and 10.
    IEnumerable<int> query = 
        numbers
        .Where((number, index) => number <= index * 10);
    IEnumerable<int> query = 
        numbers
        .AsQueryable()
        .Where((number, index) => number <= index * 10);
    
    foreach (int number in query)
        Console.WriteLine(number);
    
    /*
        This code produces the following output:
    
        0
        20
        15
        40
    */
    

Quantifier Operations

  • 수량자 작업은 시퀀스에서 조건을 충족하는 요소가
    일부인지 전체인지를 나타내는 Boolean 값.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    All모든 요소가 조건을 만족하는지를 확인.해당 사항 없음.Enumerable.All
    Queryable.All
    Any임의의 요소가 조건을 만족하는지를 확인.해당 사항 없음.Enumerable.Any
    Queryable.Any
    Contains지정된 요소가 들어 있는지를 확인.해당 사항 없음.Enumerable.Contains
    Queryable.Contains
  • All
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    
    public static void AllEx2()
    {
        List<Person> people = new List<Person>
        { 
            new Person 
            { 
              LastName = "Haas",
              Pets = new Pet[] 
              { 
                new Pet { Name="Barley", Age=10 },
                new Pet { Name="Boots", Age=14 },
                new Pet { Name="Whiskers", Age=6 }
              }
            },
            new Person 
            { 
              LastName = "Fakhouri",
              Pets = new Pet[] 
              {
                new Pet { Name = "Snowball", Age = 1}
              }
            },
            new Person 
            { 
              LastName = "Antebi",
              Pets = new Pet[] 
              { 
                new Pet { Name = "Belle", Age = 8} 
              }
            },
            new Person 
            { 
              LastName = "Philips",
              Pets = new Pet[] 
              { 
                new Pet { Name = "Sweetie", Age = 2},
                new Pet { Name = "Rover", Age = 13}
              } 
            }
        };
    
        // Determine which people have pets that are all older than 5.
        IEnumerable<Person> p = 
            people
            .Where(person => person.Pets.All(pet => pet.Age > 5));
        IEnumerable<Person> p = 
            people
            .AsQueryable()
            .Where(person => person.Pets.All(pet => pet.Age > 5));
    
        foreach (var pp in p)
        {
            Console.WriteLine(pp.LastName);
        }
          
        IEnumerable<string> names = 
            from person in people
            where person.Pets.All(pet => pet.Age > 5)
            select person.LastName;
        IEnumerable<string> names = 
            from person in people
            where person.Pets.AsQueryable().All(pet => pet.Age > 5)
            select person.LastName;
        foreach (string name in names)
        {
            Console.WriteLine(name);
        }
    
        /* This code produces the following output:
          * Haas
          * Antebi
          * Haas
          * Antebi
          */
    }
    
    class Pet
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    class Person
    {
        public string LastName { get; set; }
        public Pet[] Pets { get; set; }
    }
    
  • Any
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    
    public static void AllEx2()
    {
      List<Person> people = new List<Person>
      { 
        new Person 
        { 
          LastName = "Haas",
          Pets = new Pet[] 
          { 
            new Pet { Name="Barley", Age=10 },
            new Pet { Name="Boots", Age=14 },
            new Pet { Name="Whiskers", Age=6 }
          }
        },
        new Person 
        { 
          LastName = "Fakhouri",
          Pets = new Pet[] 
          { 
            new Pet { Name = "Snowball", Age = 1}
          }
        },
        new Person 
        { 
          LastName = "Antebi",
          Pets = new Pet[] { }
        },
        new Person 
        { 
          LastName = "Philips",
          Pets = new Pet[] 
          { 
            new Pet { Name = "Sweetie", Age = 2},
            new Pet { Name = "Rover", Age = 13}
          } 
        }
      };
                
      IEnumerable<Person> p = 
          people
          .Where(person => person.Pets.Any());
      IEnumerable<Person> p = 
          people
          .AsQueryable().Where(person => person.Pets.Any());
      foreach (var person in p)
      {
          Console.WriteLine(person.LastName);
      }
        
      // Determine which people have a non-empty Pet array.
      IEnumerable<string> names = 
          from person in people
          where person.Pets.Any()
          select person.LastName;
      IEnumerable<string> names = 
          from person in people
          where person.Pets.AsQueryable().Any()
          select person.LastName;
      foreach (string name in names)
      {
          Console.WriteLine(name);
      }
    
      /* This code produces the following output:
    
          Haas
          Fakhouri
          Philips
      */
    }
    
    class Pet
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    class Person
    {
        public string LastName { get; set; }
        public Pet[] Pets { get; set; }
    }
    
  • Contains
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    string[] fruits = { "apple", "banana", "mango", 
                      "orange", "passionfruit", "grape" };
    string fruit = "mango";
    bool hasMango = 
        fruits
        .Contains(fruit);
    bool hasMango = 
        fruits
        .AsQueryable()  
        .Contains(mango);
    Console.WriteLine(
        "The array {0} contain '{1}'.",
        hasMango ? "does" : "does not",
        fruit);
    
    // This code produces the following output:
    //
    // The array does contain 'mango'.
    

Projection Operations

  • 프로젝션은 주로 이후에 사용할 속성으로만 구성된
    새 양식으로 개체를 변환하는 작업을 가리킵니다.
  • 프로젝션을 사용하면 각 개체를 기반으로 만들어지는
    새 형식을 생성할 수 있습니다.
  • 속성을 프로젝션하고 속성에서 수학 함수를 수행할 수 있습니다.
  • 원래 개체를 변경하지 않고 프로젝션할 수도 있습니다.

Select 및 SelectMany

  • 둘 다의 작업은 소스 값에서 결과 값(value (or values))을 생성.
  • Select()는 모든 소스 값에 대해 하나의 결과 값을 생성합니다.
    따라서 전체 결과는 소스 컬렉션과 동일한 개수의 요소가 들어 있는 컬렉션.
  • SelectMany()는 각 소스 값에서 연결된 하위 컬렉션을 포함하는
    하나의 전체 결과를 생성.
  • SelectMany()에 대한 인수로 전달되는 변환 함수는
    각 소스 값에 대해 열거 가능한 값 시퀀스를 반환해야 한다.
    이러한 열거 가능한 시퀀스는 SelectMany()에 의해 연결되어
    하나의 큰 시퀀스를 만든다.

  • Select - SelectMany
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    
    class Bouquet  
    {  
      public List<string> Flowers { get; set; }  
    }  
    
    static void SelectVsSelectMany()  
    {  
      List<Bouquet> bouquets = new List<Bouquet>() {  
          new Bouquet{ Flowers = new List<string> { "sunflower", "daisy", "daffodil", "larkspur" }},  
          new Bouquet{ Flowers = new List<string> { "tulip", "rose", "orchid" }},  
          new Bouquet{ Flowers = new List<string> { "gladiolis", "lily", "snapdragon", "aster", "protea" }},  
          new Bouquet{ Flowers = new List<string> { "larkspur", "lilac", "iris", "dahlia" }}  
      };  
    
      // *********** Select ***********
      IEnumerable<List<string>> query1 = 
          bouquets
          .Select(bq => bq.Flowers);
      var query1_1 = 
          from bq in bouquets
          select bq.Flowers;
        
      Console.WriteLine("\nResults by using Select(): method");  
      // Note the extra foreach loop here.  
      foreach (IEnumerable<String> collection in query1)
      {
          foreach (string item in collection)
          {
              Console.WriteLine(item);
          }  
      }
      Console.WriteLine("\nResults by using Select(): expression");
      foreach (List<string> item in query1_1)
      {
          foreach (string sitem in item)
          {
              Console.WriteLine(sitem);
          }
      }
        
      // ********* SelectMany *********  
      IEnumerable<string> query2 = 
          bouquets
          .SelectMany(bq => bq.Flowers);
      var query2_2 = 
          from bq in bouquets
          from fl in bq.Flowers
          select fl;
      var query2_3 = 
          from bq in bouquets
          select bq.Flowers into fl
          from f in fl
          select f;
        
      Console.WriteLine("\nResults by using SelectMany(): method");
      foreach (string item in query2)
      {
          Console.WriteLine(item);
      }
      Console.WriteLine("\nResults by using SelectMany(): expression1");
      foreach (string item in query2_2)
      {
          Console.WriteLine(item);
      }
      Console.WriteLine("\nResults by using SelectMany(): expression2");
      foreach (string item in query2_3)
      {
          Console.WriteLine(item);
      }
    /*
    Results by using Select(): method
    sunflower
    daisy
    daffodil
    larkspur
    tulip
    rose
    orchid
    gladiolis
    lily
    snapdragon
    aster
    protea
    larkspur
    lilac
    iris
    dahlia
    
    Results by using Select(): expression
    sunflower
    daisy
    daffodil
    larkspur
    tulip
    rose
    orchid
    gladiolis
    lily
    snapdragon
    aster
    protea
    larkspur
    lilac
    iris
    dahlia
    
    Results by using SelectMany(): method
    sunflower
    daisy
    daffodil
    larkspur
    tulip
    rose
    orchid
    gladiolis
    lily
    snapdragon
    aster
    protea
    larkspur
    lilac
    iris
    dahlia
    
    Results by using SelectMany(): expression1
    sunflower
    daisy
    daffodil
    larkspur
    tulip
    rose
    orchid
    gladiolis
    lily
    snapdragon
    aster
    protea
    larkspur
    lilac
    iris
    dahlia
    
    Results by using SelectMany(): expression2
    sunflower
    daisy
    daffodil
    larkspur
    tulip
    rose
    orchid
    gladiolis
    lily
    snapdragon
    aster
    protea
    larkspur
    lilac
    iris
    dahlia
    */
    
    • 비교하자면 이런 차이.
    • select로 나올 수 있는 결과값이
      각각 단일 개체가 아닌
      하위에 다시 컬렉션 형태를 갖고있는 경우
      SelectMany로 묶어 한번에 표현.
    • expression에서는 다중 from 으로 표현하던가
      쿼리결과를 다중으로 반복문을 써서 검색.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    Select변환 함수를 기반으로 하는 값을 프로젝션.selectEnumerable.Select
    Queryable.Select
    SelectMany변환 함수를 기반으로 하는 값의 시퀀스를 프로젝션한 다음
    하나의 시퀀스로 평면화합.
    여러 from 절 사용Enumerable.SelectMany
    Queryable.SelectMany
  • Select
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    string[] fruits = { "apple", "banana", "mango", 
                        "orange","passionfruit", "grape" };
    
    // Project an anonymous type that contains the
    // index of the string in the source array, and
    // a string that contains the same number of characters
    // as the string's index in the source array.
    var query =
        fruits
        .Select((fruit, index) => new { index, str = fruit.Substring(0, index) });
    var query = 
        fruits
        .AsQueryable()
        .Select((fruit, index) => new { index, str = fruit.Substring(0, index) });
    
    foreach (var obj in query)
        Console.WriteLine("{0}", obj);
    
    /*
        This code produces the following output:
    
        { index = 0, str =  }
        { index = 1, str = b }
        { index = 2, str = ma }
        { index = 3, str = ora }
        { index = 4, str = pass }
        { index = 5, str = grape }
    */
    
  • SelectMany
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    
    class PetOwner
    {
        public string Name { get; set; }
        public List<string> Pets { get; set; }
    }
    
    public static void SelectManyEx2()
    {
      PetOwner[] petOwners = 
      { 
        new PetOwner 
        { 
          Name="Higa, Sidney", 
          Pets = new List<string>{ "Scruffy", "Sam" } 
        },
        new PetOwner 
        {
          Name="Ashkenazi, Ronen",
          Pets = new List<string>{ "Walker", "Sugar" } 
        },
        new PetOwner 
        { 
          Name="Price, Vernette",
          Pets = new List<string>{ "Scratches", "Diesel" } 
        },
        new PetOwner 
        { 
          Name="Hines, Patrick",
          Pets = new List<string>{ "Dusty" } 
        } 
      };
    
        // For each PetOwner element in the source array,
        // project a sequence of strings where each string
        // consists of the index of the PetOwner element in the
        // source array and the name of each pet in PetOwner.Pets.
        IEnumerable<string> query =
            petOwners
            .SelectMany
            (
              (petOwner, index) => 
              petOwner.Pets.Select(pet => index + pet)
            );
        IEnumerable<string> query =
            petOwners
            .AsQueryable()
            .SelectMany
            (
              (petOwner, index) => 
              petOwner.Pets.Select(pet => index + pet)
            );
    
        foreach (string pet in query)
            Console.WriteLine(pet);
    }
    
    // This code produces the following output:
    //
    // 0Scruffy
    // 0Sam
    // 1Walker
    // 1Sugar
    // 2Scratches
    // 2Diesel
    // 3Dusty
    

Partitioning Data(C#)

  • LINQ의 분할은 요소를 다시 정렬한 후
    섹션 중 하나를 반환하지 않고
    입력 시퀀스를 두 개의 섹션으로 나눔.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    Skip시퀀스에서 지정한 위치까지 요소를 건너뜀.해당 사항 없음.Enumerable.Skip
    Queryable.Skip
    SkipWhile요소가 조건을 충족하지 않을 때까지
    조건자 함수를 기반으로 하여 요소를 건너뜀.
    해당 사항 없음.Enumerable.SkipWhile
    Queryable.SkipWhile
    Take시퀀스에서 지정된 위치까지 요소를 사용.해당 사항 없음.Enumerable.Take
    Queryable.Take
    TakeWhile요소가 조건을 충족하지 않을 때까지
    조건자 함수를 기반으로 하여 요소를 사용.
    해당 사항 없음.Enumerable.TakeWhile
    Queryable.TakeWhile
  • Skip
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    int[] grades = { 59, 82, 70, 56, 92, 98, 85 };
    
    // Sort the grades in descending order and
    // get all except the first three.
    IEnumerable<int> lowerGrades =
        grades
        .OrderByDescending(g => g)
        .Skip(3);
    IEnumerable<int> lowerGrades =
        grades
        .AsQueryable()
        .OrderByDescending(g => g)
        .Skip(3);
    
    Console.WriteLine("All grades except the top three are:");
    foreach (int grade in lowerGrades)
        Console.WriteLine(grade);
    
    /*
        This code produces the following output:
    
        All grades except the top three are:
        82
        70
        59
        56
    */
    
  • SkipWhile
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    int[] amounts = { 5000, 2500, 9000, 8000,
                        6500, 4000, 1500, 55000 };
    
    // Skip over amounts in the array until the first amount
    // that is less than or equal to the product of its
    // index in the array and 1000. Take the remaining items.
    IEnumerable<int> query =
        amounts
        .SkipWhile((amount, index) => amount > index * 1000);
    
    IEnumerable<int> query =
        amounts
        .AsQueryable()
        .SkipWhile((amount, index) => amount > index * 1000);
    
    foreach (int amount in query)
        Console.WriteLine(amount);
    
    /*
        This code produces the following output:
    
        4000
        1500
        55000
    */
    
    • 조건을 충족하면 건너뛰는거에 주의.
    • 처음 조건 만족 안하는 개체부터 이후 전부 반영
  • Take
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    int[] grades = { 59, 82, 70, 56, 92, 98, 85 };
    
    // Sort the grades in descending order and take the first three.
    IEnumerable<int> topThreeGrades =
        grades
        .OrderByDescending(grade => grade)
        .Take(3);
    IEnumerable<int> topThreeGrades =
        grades
        .AsQueryable()
        .OrderByDescending(grade => grade)
        .Take(3);
    
    Console.WriteLine("The top three grades are:");
    foreach (int grade in topThreeGrades)
        Console.WriteLine(grade);
    
    /*
        This code produces the following output:
    
        The top three grades are:
        98
        92
        85
    */
    
  • TakeWhile
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    string[] fruits = { "apple", "banana", "mango", "orange",
                          "passionfruit", "grape" };
    
    // Take strings from the array until a string
    // that is equal to "orange" is found.
    IEnumerable<string> query =
        fruits
        .TakeWhile(fruit => String.Compare("orange", fruit, true) != 0);
    IEnumerable<string> query =
        fruits
        .AsQueryable()
        .TakeWhile(fruit => String.Compare("orange", fruit, true) != 0);
    
    foreach (string fruit in query)
        Console.WriteLine(fruit);
    
    /*
        This code produces the following output:
    
        apple
        banana
        mango
    */
    
    • 조건을 충족하면 반영에 주의.
    • 처음 조건 만족 안하는 개체부터 이후 전부 건너뜀

Join Operations

  • 한 데이터 소스의 개체를 공통 특성을 공유하는
    다른 데이터 소스의 개체와 연결.

  • 서로 간의 관계를 직접 적용할 수 없는
    데이터 원본을 대상으로 하는 쿼리에서는 Join이 중요.
    • 객체 지향 프로그래밍에서 이것은
      단방향 관계의 역방향과 같이
      모델링되지 않은 객체 간의 상관 관계를 의미 할 수 있음.
    • 단방향 관계의 예로는
      Customer 클래스가 City 형식 속성을 포함하는데
      City 클래스는 Customer 개체의 컬렉션인 속성을
      포함하지 않는 경우.
    • City 개체 목록이 있는 경우
      각 도시의 모든 고객을 찾으려면
      조인 작업을 사용해야 함.
  • LINQ 프레임워크에 제공되는 조인 메서드는 Join / GroupJoin.
    • 키가 같은지 여부에 따라 두 데이터 소스의
      일치 여부를 확인하는 조인인 동등 조인을 수행.
    • 비교를 위해 Transact-SQL에서는
      ‘같음’이 아닌 ‘보다 작음’ 연산자와 같은
      조인 연산자 지원.
    • Join은 내부 조인을 구현.
      내부 조인은 다른 데이터 집합에 일치하는 항목이 있는 개체만 반환.
    • GroupJoin 메서드는
      내부 조인 및 왼쪽 우선 외부 조인의 상위 집합 구현.
    • 왼쪽 우선 외부 조인은 다른 데이터 소스에 서로 관련된 요소가 없더라도
      첫 번째(왼쪽) 데이터 소스의 각 요소를 반환.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    Join키 선택기 함수를 기준으로
    두 시퀀스를 Join한 다음
    값 쌍을 추출합니다.
    join … in … on … equals …Enumerable.Join
    Queryable.Join
    GroupJoin키 선택기 함수를 기준으로
    두 시퀀스를 Join한 다음
    결과로 생성된 일치 항목을
    요소마다 그룹화.
    join … in … on … equals … into …Enumerable.GroupJoin
    Queryable.GroupJoin
  • Join
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    
    class Person
    {
        public string Name { get; set; }
    }
    
    class Pet
    {
        public string Name { get; set; }
        public Person Owner { get; set; }
    }
    
    public static void JoinEx1()
    {
        Person magnus = new Person { Name = "Hedlund, Magnus" };
        Person terry = new Person { Name = "Adams, Terry" };
        Person charlotte = new Person { Name = "Weiss, Charlotte" };
    
        Pet barley = new Pet { Name = "Barley", Owner = terry };
        Pet boots = new Pet { Name = "Boots", Owner = terry };
        Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
        Pet daisy = new Pet { Name = "Daisy", Owner = magnus };
    
        List<Person> people = new List<Person> { magnus, terry, charlotte };
        List<Pet> pets = new List<Pet> { barley, boots, whiskers, daisy };
    
        // Join the list of Person objects and the list of Pet objects
        // to create a list of person-pet pairs where each element is
        // an anonymous type that contains the name of pet and the name
        // of the person that owns the pet.
        var query =
            people
            .Join
            (
              pets,
              person => person,
              pet => pet.Owner,
              (person, pet) =>
              new { OwnerName = person.Name, Pet = pet.Name }
            );
        var query = 
            people
            .AsQueryable()
            .Join
            (
              pets,
              person => person,
              pet => pet.Owner,
              (person, pet) =>
              new { OwnerName = person.Name, Pet = pet.Name }
            );
    
        foreach (var obj in query)
        {
            Console.WriteLine(
                "{0} - {1}",
                obj.OwnerName,
                obj.Pet);
        }
    }
    
    /*
        This code produces the following output:
    
        Hedlund, Magnus - Daisy
        Adams, Terry - Barley
        Adams, Terry - Boots
        Weiss, Charlotte - Whiskers
    */
    
  • GroupJoin
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    
    class Person
    {
        public string Name { get; set; }
    }
    
    class Pet
    {
        public string Name { get; set; }
        public Person Owner { get; set; }
    }
    
    public static void GroupJoinEx1()
    {
        Person magnus = new Person { Name = "Hedlund, Magnus" };
        Person terry = new Person { Name = "Adams, Terry" };
        Person charlotte = new Person { Name = "Weiss, Charlotte" };
    
        Pet barley = new Pet { Name = "Barley", Owner = terry };
        Pet boots = new Pet { Name = "Boots", Owner = terry };
        Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
        Pet daisy = new Pet { Name = "Daisy", Owner = magnus };
    
        List<Person> people = new List<Person> { magnus, terry, charlotte };
        List<Pet> pets = new List<Pet> { barley, boots, whiskers, daisy };
    
        // Create a list where each element is an anonymous
        // type that contains a person's name and a collection
        // of names of the pets that are owned by them.
        var query =
            people
            .GroupJoin
            (
              pets,
              person => person,
              pet => pet.Owner,
              (person, petCollection) =>
              new
              {
                OwnerName = person.Name,
                Pets = petCollection.Select(pet => pet.Name)
              }
            );
    
        var query =
            people
            .AsQueryable()
            .GroupJoin
            (
              pets,
              person => person,
              pet => pet.Owner,
              (person, petCollection) =>
              new
              {
                OwnerName = person.Name,
                Pets = petCollection.Select(pet => pet.Name)
              }
            );
    
        foreach (var obj in query)
        {
            // Output the owner's name.
            Console.WriteLine("{0}:", obj.OwnerName);
            // Output each of the owner's pet's names.
            foreach (string pet in obj.Pets)
                Console.WriteLine("  {0}", pet);
        }
    }
    
    /*
        This code produces the following output:
    
        Hedlund, Magnus:
          Daisy
        Adams, Terry:
          Barley
          Boots
        Weiss, Charlotte:
          Whiskers
    */
    

Grouping Data

  • 데이터를 그룹에 넣어
    각 그룹의 요소가 공통 특성을 공유.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    GroupBy공통 특성을 공유하는 요소를 그룹화.
    각 그룹은 IGrouping<TKey,TElement> 개체로 표시.
    group … by
    또는
    group … by … into …
    Enumerable.GroupBy
    Queryable.GroupBy
    ToLookup키 선택기 함수에 따라
    Lookup<TKey,TElement>(일대다 사전)에 요소를 삽입.
    해당 사항 없음.Enumerable.ToLookup
  • GroupBy
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    
    class Pet
    {
        public string Name { get; set; }
        public double Age { get; set; }
    }
    
    public static void GroupByEx3()
    {
        // Create a list of pets.
        List<Pet> petsList = new List<Pet>
        { 
          new Pet { Name="Barley", Age=8.3 },
          new Pet { Name="Boots", Age=4.9 },
          new Pet { Name="Whiskers", Age=1.5 },
          new Pet { Name="Daisy", Age=4.3 } 
        };
    
        // Group Pet objects by the Math.Floor of their age.
        // Then project an anonymous type from each group
        // that consists of the key, the count of the group's
        // elements, and the minimum and maximum age in the group.
        var query = petsList.GroupBy(
            pet => Math.Floor(pet.Age),
            (age, pets) => new
            {
                Key = age,
                Count = pets.Count(),
                Min = pets.Min(pet => pet.Age),
                Max = pets.Max(pet => pet.Age)
            });
        var query = petsList.AsQueryable().GroupBy(
            pet => Math.Floor(pet.Age),
            (age, pets) => new
            {
                Key = age,
                Count = pets.Count(),
                Min = pets.Min(pet => pet.Age),
                Max = pets.Max(pet => pet.Age)
            });
    
        // Iterate over each anonymous type.
        foreach (var result in query)
        {
            Console.WriteLine("\nAge group: " + result.Key);
            Console.WriteLine("Number of pets in this age group: " + result.Count);
            Console.WriteLine("Minimum age: " + result.Min);
            Console.WriteLine("Maximum age: " + result.Max);
        }
    
        /*  This code produces the following output:
    
            Age group: 8
            Number of pets in this age group: 1
            Minimum age: 8.3
            Maximum age: 8.3
    
            Age group: 4
            Number of pets in this age group: 2
            Minimum age: 4.3
            Maximum age: 4.9
    
            Age group: 1
            Number of pets in this age group: 1
            Minimum age: 1.5
            Maximum age: 1.5
        */
    }
    
  • ToLookup
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    
    class Package
    {
        public string Company { get; set; }
        public double Weight { get; set; }
        public long TrackingNumber { get; set; }
    }
    
    public static void ToLookupEx1()
    {
        // Create a list of Packages.
        List<Package> packages =
            new List<Package>
                { new Package { Company = "Coho Vineyard",
                      Weight = 25.2, TrackingNumber = 89453312L },
                  new Package { Company = "Lucerne Publishing",
                      Weight = 18.7, TrackingNumber = 89112755L },
                  new Package { Company = "Wingtip Toys",
                      Weight = 6.0, TrackingNumber = 299456122L },
                  new Package { Company = "Contoso Pharmaceuticals",
                      Weight = 9.3, TrackingNumber = 670053128L },
                  new Package { Company = "Wide World Importers",
                      Weight = 33.8, TrackingNumber = 4665518773L } };
    
        // Create a Lookup to organize the packages.
        // Use the first character of Company as the key value.
        // Select Company appended to TrackingNumber
        // as the element values of the Lookup.
        ILookup<char, string> lookup =
            packages
            .ToLookup(p => Convert.ToChar(p.Company.Substring(0, 1)),
                      p => p.Company + " " + p.TrackingNumber);
    
        // Iterate through each IGrouping in the Lookup.
        foreach (IGrouping<char, string> packageGroup in lookup)
        {
            // Print the key value of the IGrouping.
            Console.WriteLine(packageGroup.Key);
            // Iterate through each value in the
            // IGrouping and print its value.
            foreach (string str in packageGroup)
                Console.WriteLine("    {0}", str);
        }
    }
    
    /*
    This code produces the following output:
    
    C
        Coho Vineyard 89453312
        Contoso Pharmaceuticals 670053128
    L
        Lucerne Publishing 89112755
    W
        Wingtip Toys 299456122
        Wide World Importers 4665518773
    */
    

Generation Operations업

  • 생성은 값의 새 시퀀스를 만드는 작업.
  • 생성을 수행하는 표준 쿼리 연산자 메서드는 다음 섹션에 나열.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    DefaultIfEmpty빈 컬렉션을 기본값을 갖는 singleton 컬렉션으로 변환.해당 사항 없음.Enumerable.DefaultIfEmpty
    Queryable.DefaultIfEmpty
    Empty비어 있는 컬렉션을 반환.해당 사항 없음.Enumerable.Empty
    Range일련의 숫자를 포함하는 컬렉션을 생성.해당 사항 없음.Enumerable.Range
    Repeat반복되는 값이 하나 들어 있는 컬렉션을 생성.해당 사항 없음.Enumerable.Repeat
  • DefaultIfEmpty
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    
    class Pet
    {
      public string Name { get; set; }
      public int Age { get; set; }
    }
    
    public static void DefaultIfEmptyEx1()
    {
      // Create a list of Pet objects.
      List<Pet> pets = new List<Pet>
      { 
        new Pet { Name="Barley", Age=8 },
        new Pet { Name="Boots", Age=4 },
        new Pet { Name="Whiskers", Age=1 } 
      };
    
      // This query selects only those pets that are 10 or older.
      // In case there are no pets that meet that criteria, call
      // DefaultIfEmpty(). This code passes an (optional) default
      // value to DefaultIfEmpty().
      string[] oldPets =
        pets
        .Where(pet => pet.Age >= 10)
        .Select(pet => pet.Name)
        .DefaultIfEmpty("[EMPTY]")
        .ToArray();
      string[] oldPets =
        pets
        .AsQueryable()
        .Where(pet => pet.Age >= 10)
        .Select(pet => pet.Name)
        .DefaultIfEmpty("[EMPTY]")
        .ToArray();
    
      Console.WriteLine("First query: " + oldPets[0]);
    
      // This query selects only those pets that are 10 or older.
      // This code does not call DefaultIfEmpty().
      string[] oldPets2 =
        pets
        .Where(pet => pet.Age >= 10)
        .Select(pet => pet.Name)
        .ToArray();
    
      string[] oldPets2 =
        pets
        .AsQueryable()
        .Where(pet => pet.Age >= 10)
        .Select(pet => pet.Name)
        .ToArray();
    
      // There may be no elements in the array, so directly
      // accessing element 0 may throw an exception.
      try
      {
          Console.WriteLine("Second query: " + oldPets2[0]);
      }
      catch (Exception e)
      {
          Console.WriteLine("Second query: An exception was thrown: " + e.Message);
      }
    }
    
  • Empty
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    
    //example demonstrates how to use Empty<TResult>() 
    //to generate an empty IEnumerable<T>.
    IEnumerable<decimal> empty = Enumerable.Empty<decimal>();
    /////////////////////////////////////////////////////
    
    string[] names1 = { "Hartono, Tommy" };
    string[] names2 = { "Adams, Terry", "Andersen, Henriette Thaulow",
                          "Hedlund, Magnus", "Ito, Shu" };
    string[] names3 = { "Solanki, Ajay", "Hoeing, Helge",
                          "Andersen, Henriette Thaulow",
                          "Potra, Cristina", "Iallo, Lucio" };
    
    List<string[]> namesList =
        new List<string[]> { names1, names2, names3 };
    
    // Only include arrays that have four or more elements
    IEnumerable<string> allNames =
        namesList.Aggregate(Enumerable.Empty<string>(),
        (current, next) => next.Length > 3 ? current.Union(next) : current);
    
    foreach (string name in allNames)
    {
        Console.WriteLine(name);
    }
    
    /*
    This code produces the following output:
    
    Adams, Terry
    Andersen, Henriette Thaulow
    Hedlund, Magnus
    Ito, Shu
    Solanki, Ajay
    Hoeing, Helge
    Potra, Cristina
    Iallo, Lucio
    */
    
  • Range
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    // Generate a sequence of integers from 1 to 10
    // and then select their squares.
    IEnumerable<int> squares = Enumerable.Range(1, 10).Select(x => x * x);
    
    foreach (int num in squares)
    {
        Console.WriteLine(num);
    }
    
    /*
    This code produces the following output:
    
    1
    4
    9
    16
    25
    36
    49
    64
    81
    100
    */
    
  • Repeat
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    IEnumerable<string> strings =
        Enumerable.Repeat("I like programming.", 15);
    
    foreach (String str in strings)
    {
        Console.WriteLine(str);
    }
    
    /*
    This code produces the following output:
    
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    I like programming.
    */
    

Equality Operations

  • 해당 요소가 동일하고 같은 수의 요소를 포함 하는 두 시퀀스는 같은 것으로 간주.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    SequenceEqual쌍 단위 방식으로 요소를 비교하여
    두 시퀀스가 서로 같은지 확인.
    해당 사항 없음.Enumerable.SequenceEqual
    Queryable.SequenceEqual

Element Operations

  • 요소 작업은 시퀀스에서 특정 단일 요소를 반환합니다.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    ElementAt컬렉션의 지정된 인덱스에 있는 요소를 반환.해당 사항 없음.Enumerable.ElementAt
    Queryable.ElementAt
    ElementAtOrDefault컬렉션의 지정된 인덱스에 있는 요소를 반환하거나
    인덱스가 범위를 벗어나면 기본값을 반환.
    해당 사항 없음.Enumerable.ElementAtOrDefault
    Queryable.ElementAtOrDefault
    First컬렉션의 첫 번째 요소 또는
    특정 조건에 맞는 첫 번째 요소를 반환.
    해당 사항 없음.Enumerable.First
    Queryable.First
    FirstOrDefault컬렉션의 첫 번째 요소 또는
    특정 조건에 맞는 첫 번째 요소를 반환.
    이러한 요소가 없으면 기본값을 반환.
    해당 사항 없음.Enumerable.FirstOrDefault
    Queryable.FirstOrDefault
    Queryable.FirstOrDefault<TSource>(IQueryable<TSource>)
    Last컬렉션의 마지막 요소 또는
    특정 조건에 맞는 마지막 요소를 반환.
    해당 사항 없음.Enumerable.Last
    Queryable.Last
    LastOrDefault컬렉션의 마지막 요소 또는
    특정 조건에 맞는 마지막 요소를 반환.
    이러한 요소가 없으면 기본값을 반환.
    해당 사항 없음.Enumerable.LastOrDefault
    Queryable.LastOrDefault
    Single컬렉션의 유일한 요소 또는
    특정 조건에 맞는 유일한 요소를 반환.
    반환할 요소가 없거나 두 개 이상 있는 경우
    InvalidOperationException을 throw.
    해당 사항 없음.Enumerable.Single
    Queryable.Single
    SingleOrDefault컬렉션의 유일한 요소 또는
    특정 조건에 맞는 유일한 요소를 반환.
    반환할 요소가 없는 경우 기본값을 반환.
    반환할 요소가 두 개 이상 있는 경우
    InvalidOperationException을 throw.
    해당 사항 없음.Enumerable.SingleOrDefault
    Queryable.SingleOrDefault
  • ElementAt
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    string[] names = { "Hartono, Tommy", "Adams, Terry",
                      "Andersen, Henriette Thaulow",
                      "Hedlund, Magnus", "Ito, Shu" };
    
    Random random = new Random(DateTime.Now.Millisecond);
    
    string name = 
        names
        .ElementAt(random.Next(0, names.Length));
    string name =
        names
        .AsQueryable()
        .ElementAt(random.Next(0, names.Length));
    
    Console.WriteLine("The name chosen at random is '{0}'.", name);
    
    /*
        This code produces the following sample output.
        Yours may be different due to the use of Random.
    
        The name chosen at random is 'Ito, Shu'.
    */
    
  • ElementAtOrDefault
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    string[] names = { "Hartono, Tommy", "Adams, Terry",
                      "Andersen, Henriette Thaulow",
                      "Hedlund, Magnus", "Ito, Shu" };
    
    int index = 20;
    
    string name = 
        names
        .ElementAtOrDefault(index);
    string name = 
        names
        .AsQueryable()
        .ElementAtOrDefault(index);
    
    Console.WriteLine(
        "The name chosen at index {0} is '{1}'.",
        index,
        String.IsNullOrEmpty(name) ? "[NONE AT THIS INDEX]" : name);
    
    /*
        This code produces the following output:
    
        The name chosen at index 20 is '[NONE AT THIS INDEX]'.
    */
    
  • First
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    int[] numbers = { 9, 34, 65, 92, 87, 435, 3, 54,
                      83, 23, 87, 435, 67, 12, 19 };
    
    // Get the first number in the array that is greater than 80.
    int first = 
        numbers
        .First(number => number > 80);
    int first = 
        numbers
        .AsQueryable()
        .First(number => number > 80);
    
    Console.WriteLine(first);
    
    /*
        This code produces the following output:
    
        92
    */
    
  • FirstOrDefault
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    
    string[] names = { "Hartono, Tommy", "Adams, Terry",
                        "Andersen, Henriette Thaulow",
                        "Hedlund, Magnus", "Ito, Shu" };
    
    // Get the first string in the array that is longer
    // than 20 characters, or the default value for type
    // string (null) if none exists.
    string firstLongName = 
        names
        .FirstOrDefault(name => name.Length > 20);
    string firstLongName =
        names
        .AsQueryable()
        .FirstOrDefault(name => name.Length > 20);
    
    Console.WriteLine("The first long name is '{0}'.", firstLongName);
    
    // Get the first string in the array that is longer
    // than 30 characters, or the default value for type
    // string (null) if none exists.
    string firstVeryLongName = 
        names
        .FirstOrDefault(name => name.Length > 30);
    string firstVeryLongName =
        names
        .AsQueryable()
        .FirstOrDefault(name => name.Length > 30);
    
    Console.WriteLine(
        "There is {0} name that is longer than 30 characters.",
        string.IsNullOrEmpty(firstVeryLongName) ? "NOT a" : "a");
    
    /*
        This code produces the following output:
    
        The first long name is 'Andersen, Henriette Thaulow'.
        There is NOT a name that is longer than 30 characters.
    */
    
  • Last
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    int[] numbers = { 9, 34, 65, 92, 87, 435, 3, 54,
                        83, 23, 87, 67, 12, 19 };
    
    // Get the last number in the array that is greater than 80.
    int last = 
        numbers
        .Last(num => num > 80);
    int last = 
        numbers
        .AsQueryable()
        .Last(num => num > 80);
    
    Console.WriteLine(last);
    
    /*
        This code produces the following output:
    
        87
    */
    
  • LastOrDefault
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    
    double[] numbers = { 49.6, 52.3, 51.0, 49.4, 50.2, 48.3 };
    
    // Get the last number in the array that rounds to 50.0,
    // or else the default value for type double (0.0).
    double last50 = 
        numbers
        .LastOrDefault(n => Math.Round(n) == 50.0);
    double last50 =
        numbers
        .AsQueryable()
        .LastOrDefault(n => Math.Round(n) == 50.0);
    
    Console.WriteLine("The last number that rounds to 50 is {0}.", last50);
    
    // Get the last number in the array that rounds to 40.0,
    // or else the default value for type double (0.0).
    double last40 = 
        numbers
        .LastOrDefault(n => Math.Round(n) == 40.0);
    double last40 =
        numbers
        .AsQueryable()
        .LastOrDefault(n => Math.Round(n) == 40.0);
    
    Console.WriteLine(
        "The last number that rounds to 40 is {0}.",
        last40 == 0.0 ? "[DOES NOT EXIST]" : last40.ToString());
    
    /*
        This code produces the following output:
    
        The last number that rounds to 50 is 50.2.
        The last number that rounds to 40 is [DOES NOT EXIST].
    */
    
  • Single
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    
    string[] fruits = { "apple", "banana", "mango",
                          "orange", "passionfruit", "grape" };
    
    // Get the only string in the array whose length is greater than 10.
    string fruit1 = 
        fruits
        .Single(fruit => fruit.Length > 10);
    string fruit1 = 
        fruits
        .AsQueryable()
        .Single(fruit => fruit.Length > 10);
    
    Console.WriteLine("First Query: " + fruit1);
    
    try
    {
        // Try to get the only string in the array
        // whose length is greater than 15.
        string fruit2 = 
            fruits
            .Single(fruit => fruit.Length > 15);
        string fruit2 = 
            fruits
            .AsQueryable()
            .Single(fruit => fruit.Length > 15);
          
        Console.WriteLine("Second Query: " + fruit2);
    }
    catch (System.InvalidOperationException)
    {
        Console.Write("Second Query: The collection does not contain ");
        Console.WriteLine("exactly one element whose length is greater than 15.");
    }
    
    /*
        This code produces the following output:
    
        First Query: passionfruit
        Second Query: The collection does not contain exactly one
        element whose length is greater than 15.
    */
    
  • SingleOrDefault
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    
    string[] fruits = { "apple", "banana", "mango",
                          "orange", "passionfruit", "grape" };
    
    // Get the single string in the array whose length is greater
    // than 10, or else the default value for type string (null).
    string fruit1 = 
        fruits
        .SingleOrDefault(fruit => fruit.Length > 10);
    string fruit1 =
        fruits
        .AsQueryable()
        .SingleOrDefault(fruit => fruit.Length > 10);
    
    Console.WriteLine("First Query: " + fruit1);
    
    // Get the single string in the array whose length is greater
    // than 15, or else the default value for type string (null).
    string fruit2 =
        fruits
        .SingleOrDefault(fruit => fruit.Length > 15);
    
    string fruit2 =
      fruits
      .AsQueryable()
      .SingleOrDefault(fruit => fruit.Length > 15);
    
    Console.WriteLine("Second Query: " +
        (String.IsNullOrEmpty(fruit2) ? "No such string!" : fruit2));
    
    /*
        This code produces the following output:
    
        First Query: passionfruit
        Second Query: No such string!
    */
    

Converting Data Types

  • 변환 메서드는 입력 개체의 형식을 변경.
  • LINQ 쿼리의 변환 작업은 다양한 애플리케이션에서 유용.
    • Enumerable.AsEnumerable 메서드는
      표준 쿼리 연산자의 형식 사용자 지정 구현을 숨기는 데 사용.
    • Enumerable.OfType 메서드는
      LINQ 쿼리에 대해 매개 변수가 없는 컬렉션을 사용하도록 설정
    • Enumerable.ToArray, Enumerable.ToDictionary,
      Enumerable.ToList, Enumerable.ToLookup 메서드는
      쿼리가 열거될 때까지 연기하는 대신
      강제로 쿼리를 즉시 실행하는 데 사용.

메서드

  • 이 표에서 이름이 “As”로 시작하는 변환 메서드는
    소스 컬렉션의 정적 형식을 변경하지만 열거하지는 않음.
    이름이 “To”로 시작하는 메서드는 소스 컬렉션을 열거하고
    항목을 해당하는 컬렉션 형식에 삽입.
  • 이름설명C# 쿼리 식 구문추가 정보
    AsEnumerableIEnumerable<T>로 형식화된 입력을 반환.해당 사항 없음.Enumerable.AsEnumerable
    AsQueryable(generic)IEnumerable을 (generic)IQueryable로 변환.해당 사항 없음.Queryable.AsQueryable
    Cast컬렉션의 요소를 지정된 형식으로 캐스트.명시적 형식 범위 변수 사용.
    예를 들어:
    from string str in words
    Enumerable.Cast
    Queryable.Cast
    OfType지정된 형식으로 캐스트할 수 있는지 여부에 따라 값을 필터링.해당 사항 없음.Enumerable.OfType
    Queryable.OfType
    ToArray컬렉션을 배열로 변환합니다.
    이 메서드는 쿼리를 강제로 실행.
    해당 사항 없음.Enumerable.ToArray
    ToDictionary키 선택기 함수에 따라
    Dictionary<TKey,TValue>에 요소를 배치.
    이 메서드는 쿼리를 강제로 실행.
    해당 사항 없음.Enumerable.ToDictionary
    ToList컬렉션을 List<T>로 변환.
    이 메서드는 쿼리를 강제로 실행.
    해당 사항 없음.Enumerable.ToList
    ToLookup키 선택기 함수에 따라
    Lookup<TKey,TElement>(일 대 다 사전)에 요소를 배치.
    이 메서드는 쿼리를 강제로 실행.
    해당 사항 없음.Enumerable.ToLookup
  • AsEnumerable
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    
    // Custom class.
    class Clump<T> : List<T>
    {
        // Custom implementation of Where().
        public IEnumerable<T> Where(Func<T, bool> predicate)
        {
            Console.WriteLine("In Clump's implementation of Where().");
            return Enumerable.Where(this, predicate);
        }
    }
    
    static void AsEnumerableEx1()
    {
        // Create a new Clump<T> object.
        Clump<string> fruitClump =
            new Clump<string> { "apple", "passionfruit", "banana",
                "mango", "orange", "blueberry", "grape", "strawberry" };
    
        // First call to Where():
        // Call Clump's Where() method with a predicate.
        IEnumerable<string> query1 =
            fruitClump.Where(fruit => fruit.Contains("o"));
    
        Console.WriteLine("query1 has been created.\n");
    
        // Second call to Where():
        // First call AsEnumerable() to hide Clump's Where() method and thereby
        // force System.Linq.Enumerable's Where() method to be called.
        IEnumerable<string> query2 =
            fruitClump.AsEnumerable().Where(fruit => fruit.Contains("o"));
    
        // Display the output.
        Console.WriteLine("query2 has been created.");
    }
    
    // This code produces the following output:
    //
    // In Clump's implementation of Where().
    // query1 has been created.
    //
    // query2 has been created.
    
  • AsQueryable
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    List<int> grades = new List<int> { 78, 92, 100, 37, 81 };
    
    // Convert the List to an IQueryable<int>.
    IQueryable<int> iqueryable = grades.AsQueryable();
    
    // Get the Expression property of the IQueryable object.
    System.Linq.Expressions.Expression expressionTree =
        iqueryable.Expression;
    
    Console.WriteLine("The NodeType of the expression tree is: "
        + expressionTree.NodeType.ToString());
    Console.WriteLine("The Type of the expression tree is: "
        + expressionTree.Type.Name);
    
    /*
        This code produces the following output:
    
        The NodeType of the expression tree is: Constant
        The Type of the expression tree is: EnumerableQuery`1
    */
    
  • Cast
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    
    // Create a list of objects.
    List<object> words =
        new List<object> { "green", "blue", "violet" };
    
    // Cast the objects in the list to type 'string'
    // and project the first letter of each string.
    
    IEnumerable<string> query1 =
        words.AsQueryable()
        .Cast<string>()
        .Select(str => str.Substring(0, 1));
    
    IEnumerable<string> query2 =
        words
        .Cast<string>()
        .Select(str => str.Substring(0, 1));
    
    foreach (string s in query1)
        Console.WriteLine(s);
    
    
    foreach (string s in query2)
        Console.WriteLine(s);
    
    /*  This code produces the following output:
    
        g
        b
        v
    */
    
    
  • OfType
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    
    System.Collections.ArrayList fruits = new System.Collections.ArrayList(4);
    fruits.Add("Mango");
    fruits.Add("Orange");
    fruits.Add("Apple");
    fruits.Add(3.0);
    fruits.Add("Banana");
    
    // Apply OfType() to the ArrayList.
    IEnumerable<string> query1 = fruits.OfType<string>();
    
    Console.WriteLine("Elements of type 'string' are:");
    foreach (string fruit in query1)
    {
        Console.WriteLine(fruit);
    }
    
    // The following query shows that the standard query operators such as
    // Where() can be applied to the ArrayList type after calling OfType().
    IEnumerable<string> query2 =
        fruits
        .OfType<string>()
        .Where(fruit => fruit.ToLower()
        .Contains("n"));
    IEnumerable<string> query2 =
        fruits
        .OfType<string>()
        .AsQueryable()
        .Where(fruit => fruit.ToLower().Contains("n"));
    
    Console.WriteLine("\nThe following strings contain 'n':");
    foreach (string fruit in query2)
    {
        Console.WriteLine(fruit);
    }
    
    // This code produces the following output:
    //
    // Elements of type 'string' are:
    // Mango
    // Orange
    // Apple
    // Banana
    //
    // The following strings contain 'n':
    // Mango
    // Orange
    // Banana
    
  • ToArray
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    class Package
    {
        public string Company { get; set; }
        public double Weight { get; set; }
    }
    
    public static void ToArrayEx1()
    {
        List<Package> packages = new List<Package>
          { new Package { Company = "Coho Vineyard", Weight = 25.2 },
            new Package { Company = "Lucerne Publishing", Weight = 18.7 },
            new Package { Company = "Wingtip Toys", Weight = 6.0 },
            new Package { Company = "Adventure Works", Weight = 33.8 } };
    
        string[] companies = packages.Select(pkg => pkg.Company).ToArray();
    
        foreach (string company in companies)
        {
            Console.WriteLine(company);
        }
    }
    
    /*
    This code produces the following output:
    
    Coho Vineyard
    Lucerne Publishing
    Wingtip Toys
    Adventure Works
    */
    
  • ToDictionary
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    
    class Package
    {
        public string Company { get; set; }
        public double Weight { get; set; }
        public long TrackingNumber { get; set; }
    }
    
    public static void ToDictionaryEx1()
    {
        List<Package> packages =
            new List<Package>
                { new Package { Company = "Coho Vineyard", Weight = 25.2, TrackingNumber = 89453312L },
                  new Package { Company = "Lucerne Publishing", Weight = 18.7, TrackingNumber = 89112755L },
                  new Package { Company = "Wingtip Toys", Weight = 6.0, TrackingNumber = 299456122L },
                  new Package { Company = "Adventure Works", Weight = 33.8, TrackingNumber = 4665518773L } };
    
        // Create a Dictionary of Package objects,
        // using TrackingNumber as the key.
        Dictionary<long, Package> dictionary =
            packages.ToDictionary(p => p.TrackingNumber);
    
        foreach (KeyValuePair<long, Package> kvp in dictionary)
        {
            Console.WriteLine(
                "Key {0}: {1}, {2} pounds",
                kvp.Key,
                kvp.Value.Company,
                kvp.Value.Weight);
        }
    }
    
    /*
    This code produces the following output:
    
    Key 89453312: Coho Vineyard, 25.2 pounds
    Key 89112755: Lucerne Publishing, 18.7 pounds
    Key 299456122: Wingtip Toys, 6 pounds
    Key 4665518773: Adventure Works, 33.8 pounds
    */
    
  • ToList
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    string[] fruits = { "apple", "passionfruit", "banana", "mango",
                          "orange", "blueberry", "grape", "strawberry" };
    
    List<int> lengths = fruits.Select(fruit => fruit.Length).ToList();
    
    foreach (int length in lengths)
    {
        Console.WriteLine(length);
    }
    
    /*
    This code produces the following output:
    
    5
    12
    6
    5
    6
    9
    5
    10
    */
    
  • ToLookup
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    
    class Package
    {
        public string Company { get; set; }
        public double Weight { get; set; }
        public long TrackingNumber { get; set; }
    }
    
    public static void ToLookupEx1()
    {
        // Create a list of Packages.
        List<Package> packages = new List<Package>
        { 
          new Package { 
            Company = "Coho Vineyard",
            Weight = 25.2, 
            TrackingNumber = 89453312L },
          new Package { 
            Company = "Lucerne Publishing",
            Weight = 18.7, 
            TrackingNumber = 89112755L },
          new Package { 
            Company = "Wingtip Toys",
            Weight = 6.0, 
            TrackingNumber = 299456122L },
          new Package { 
            Company = "Contoso Pharmaceuticals",
            Weight = 9.3, 
            TrackingNumber = 670053128L },
          new Package { 
            Company = "Wide World Importers",
            Weight = 33.8, 
            TrackingNumber = 4665518773L } 
          };
    
        // Create a Lookup to organize the packages.
        // Use the first character of Company as the key value.
        // Select Company appended to TrackingNumber
        // as the element values of the Lookup.
        ILookup<char, string> lookup =
            packages
            .ToLookup(p => Convert.ToChar(p.Company.Substring(0, 1)),
                      p => p.Company + " " + p.TrackingNumber);
    
        // Iterate through each IGrouping in the Lookup.
        foreach (IGrouping<char, string> packageGroup in lookup)
        {
            // Print the key value of the IGrouping.
            Console.WriteLine(packageGroup.Key);
            // Iterate through each value in the
            // IGrouping and print its value.
            foreach (string str in packageGroup)
                Console.WriteLine("    {0}", str);
        }
    }
    
    /*
    This code produces the following output:
    
    C
        Coho Vineyard 89453312
        Contoso Pharmaceuticals 670053128
    L
        Lucerne Publishing 89112755
    W
        Wingtip Toys 299456122
        Wide World Importers 4665518773
    */
    

Concatenation Operations

  • 연결은 한 시퀀스를 다른 시퀀스에 추가하는 작업.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    Concat두 시퀀스를 연결헤 하나의 시퀀스를 구성.해당 사항 없음.Enumerable.Concat
    Queryable.Concat
  • Concat
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    
    class Pet
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    
    // This method creates and returns an array of Pet objects.
    static Pet[] GetCats()
    {
        Pet[] cats = { new Pet { Name="Barley", Age=8 },
                      new Pet { Name="Boots", Age=4 },
                      new Pet { Name="Whiskers", Age=1 } };
        return cats;
    }
    
    // This method creates and returns an array of Pet objects.
    static Pet[] GetDogs()
    {
        Pet[] dogs = { new Pet { Name="Bounder", Age=3 },
                      new Pet { Name="Snoopy", Age=14 },
                      new Pet { Name="Fido", Age=9 } };
        return dogs;
    }
    
    public static void ConcatEx1()
    {
        Pet[] cats = GetCats();
        Pet[] dogs = GetDogs();
    
        // Concatenate a collection of cat names to a
        // collection of dog names by using Concat().
          
        IEnumerable<string> query =
            cats
            .Select(cat => cat.Name)
            .Concat(dogs.Select(dog => dog.Name));
        IEnumerable<string> query =
            cats
            .AsQueryable()
            .Select(cat => cat.Name)
            .Concat(dogs.Select(dog => dog.Name));
    
        foreach (string name in query)
            Console.WriteLine(name);
    }
    
    // This code produces the following output:
    //
    // Barley
    // Boots
    // Whiskers
    // Bounder
    // Snoopy
    // Fido
    
    ///////////////////////////////////////////////////////////
    // vs selectmany
    Pet[] cats = GetCats();
    Pet[] dogs = GetDogs();
    
    IEnumerable<string> query =
        new[] { cats.Select(cat => cat.Name), dogs.Select(dog => dog.Name) }
        .SelectMany(name => name);
    
    foreach (string name in query)
    {
        Console.WriteLine(name);
    }
    
    // This code produces the following output:
    //
    // Barley
    // Boots
    // Whiskers
    // Bounder
    // Snoopy
    // Fido
    

Aggregation Operations

  • 값의 컬렉션에서 하나의 값을 계산.
  • 예를 들어 1달 동안의 일일 온도 값에서 평균 일일 온도를 계산.

메서드

  • 이름설명C# 쿼리 식 구문추가 정보
    Aggregate컬렉션 값에 대해 사용자 지정 집계 작업을 수행.해당 사항 없음.Enumerable.Aggregate
    Queryable.Aggregate
    Average값 컬렉션의 평균 값을 계산.해당 사항 없음.Enumerable.Average
    Queryable.Average
    Count컬렉션에서 조건자 함수를 충족하는 개수를 계산.해당 사항 없음.Enumerable.Count
    Queryable.Count
    LongCount큰 컬렉션에서 조건자 함수를 충족하는 개수를 계산.해당 사항 없음.Enumerable.LongCount
    Queryable.LongCount
    Max컬렉션의 최대값.해당 사항 없음.Enumerable.Max
    Queryable.Max
    Min컬렉션의 최소값.해당 사항 없음.Enumerable.Min
    Queryable.Min
    Sum컬렉션에 있는 값의 합계.해당 사항 없음.Enumerable.Sum
    Queryable.Sum
  • Aggregate
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
    
    // Determine whether any string in the array is longer than "banana".
    // Return the final result as an upper case string.
    string longestName =
        fruits
        .Aggregate("banana",
                  (longest, next) => next.Length > longest.Length 
                  ? next : longest, fruit => fruit.ToUpper());
    
    string longestName =
        fruits
        .AsQueryable()
        .Aggregate("banana",
                  (longest, next) => next.Length > longest.Length 
                  ? next : longest,fruit => fruit.ToUpper());
    
    Console.WriteLine(
        "The fruit with the longest name is {0}.",
        longestName);
    
    // This code produces the following output:
    //
    // The fruit with the longest name is PASSIONFRUIT.
    
  • Average
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    string[] fruits = { "apple", "banana", "mango", "orange", "passionfruit", "grape" };
    
    // Determine the average string length in the array.
    double average = 
        fruits
        .Average(s => s.Length);
    double average = 
        fruits
        .AsQueryable()
        .Average(s => s.Length);
    
    Console.WriteLine("The average string length is {0}.", average);
    
    // This code produces the following output:
    //
    // The average string length is 6.5.
    
  • Count
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    class Pet
    {
        public string Name { get; set; }
        public bool Vaccinated { get; set; }
    }
    
    public static void CountEx2()
    {
        // Create an array of Pet objects.
        Pet[] pets = { new Pet { Name="Barley", Vaccinated=true },
                      new Pet { Name="Boots", Vaccinated=false },
                      new Pet { Name="Whiskers", Vaccinated=false } };
    
        // Count the number of unvaccinated pets in the array.
        int numberUnvaccinated = 
            pets
            .Count(p => p.Vaccinated == false);
        int numberUnvaccinated =
            pets
            .AsQueryable()
            .Count(p => p.Vaccinated == false);
    
        Console.WriteLine(
            "There are {0} unvaccinated animals.",
            numberUnvaccinated);
    }
    
    // This code produces the following output:
    //
    // There are 2 unvaccinated animals.
    
  • LongCount
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    
    class Pet
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    
    public static void LongCountEx2()
    {
        Pet[] pets = { new Pet { Name="Barley", Age=8 },
                      new Pet { Name="Boots", Age=4 },
                      new Pet { Name="Whiskers", Age=1 } };
    
        const int Age = 3;
    
        // Count the number of Pet objects where Pet.Age is greater than 3.
        long count = 
            pets
            .LongCount(pet => pet.Age > Age);
        long count = 
            pets
            .AsQueryable()
            .LongCount(pet => pet.Age > Age);
    
        Console.WriteLine("There are {0} animals over age {1}.", count, Age);
    }
    
    /*
        This code produces the following output:
    
        There are 2 animals over age 3.
    */
    
  • Max
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    class Pet
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    
    public static void MaxEx2()
    {
        Pet[] pets = { new Pet { Name="Barley", Age=8 },
                      new Pet { Name="Boots", Age=4 },
                      new Pet { Name="Whiskers", Age=1 } };
    
        // Add Pet.Age to the length of Pet.Name
        // to determine the "maximum" Pet object in the array.
        int max = 
            pets
            .Max(pet => pet.Age + pet.Name.Length);
        int max =
            pets
            .AsQueryable()
            .Max(pet => pet.Age + pet.Name.Length);
    
        Console.WriteLine(
            "The maximum pet age plus name length is {0}.",
            max);
    }
    
    /*
        This code produces the following output:
    
        The maximum pet age plus name length is 14.
    */
    
  • Min
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    
    class Pet
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    
    public static void MinEx2()
    {
        Pet[] pets = { new Pet { Name="Barley", Age=8 },
                      new Pet { Name="Boots", Age=4 },
                      new Pet { Name="Whiskers", Age=1 } };
    
        // Get the Pet object that has the smallest Age value.
        int min = 
            pets
            .Min(pet => pet.Age);
        int min = 
            pets
            .AsQueryable()
            .Min(pet => pet.Age);
    
        Console.WriteLine("The youngest animal is age {0}.", min);
    }
    
    /*
        This code produces the following output:
    
        The youngest animal is age 1.
    */
    
  • Sum
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    class Package
    {
        public string Company { get; set; }
        public double Weight { get; set; }
    }
    
    public static void SumEx3()
    {
        List<Package> packages =
            new List<Package>
                { new Package { Company = "Coho Vineyard", Weight = 25.2 },
                  new Package { Company = "Lucerne Publishing", Weight = 18.7 },
                  new Package { Company = "Wingtip Toys", Weight = 6.0 },
                  new Package { Company = "Adventure Works", Weight = 33.8 } };
    
        // Calculate the sum of all package weights.
        double totalWeight = 
            packages
            .Sum(pkg => pkg.Weight);
        double totalWeight = 
            packages
            .AsQueryable()
            .Sum(pkg => pkg.Weight);
    
        Console.WriteLine("The total weight of the packages is: {0}", totalWeight);
    }
    
    /*
        This code produces the following output:
    
        The total weight of the packages is: 83.7
    */
    

참고

This post is licensed under CC BY 4.0 by the author.

13. LINQ 1

15. Delegate, Event

Comments powered by Disqus.