dev/asp.net, c#

[c#] LINQ 컬렉션 표준 쿼리 메서드 5 - (프로젝션, 요소) Select, SelectMany, Zip, ElementAt, First, Last, Single

코딩for 2022. 11. 16. 10:21
반응형

 

컬렉션 작업을 할때 가장 많이 이용하는 함수이기도 한 프로젝션과 요소작업 컬렉션 메소드에 대해 알아봅니다.

메서드

메서드 이름 설명 C# 쿼리 식 구문
Select 변환 함수를 기반으로 하는 값을 프로젝션합니다. select
SelectMany 변환 함수를 기반으로 하는 값의 시퀀스를 프로젝션한 다음 하나의 시퀀스로 평면화합니다. 여러 from 절 사용
Zip 지정된 2~3개 시퀀스의 요소를 사용하여 튜플 시퀀스를 생성합니다.  
ElementAt 컬렉션의 지정된 인덱스에 있는 요소를 반환합니다.  
ElementAtOrDefault 컬렉션의 지정된 인덱스에 있는 요소를 반환하거나 인덱스가 범위를 벗어나면 기본값을 반환합니다.  
First 컬렉션의 첫 번째 요소 또는 특정 조건에 맞는 첫 번째 요소를 반환합니다.  
FirstOrDefault 컬렉션의 첫 번째 요소 또는 특정 조건에 맞는 첫 번째 요소를 반환합니다. 이러한 요소가 없으면 기본값을 반환합니다.  
Last 컬렉션의 마지막 요소 또는 특정 조건에 맞는 마지막 요소를 반환합니다.  
LastOrDefault 컬렉션의 마지막 요소 또는 특정 조건에 맞는 마지막 요소를 반환합니다. 이러한 요소가 없으면 기본값을 반환합니다.  
Single 컬렉션의 유일한 요소 또는 특정 조건에 맞는 유일한 요소를 반환합니다. 반환할 요소가 없거나 두 개 이상 있는 경우 InvalidOperationException을 throw합니다.  
SingleOrDefault 컬렉션의 유일한 요소 또는 특정 조건에 맞는 유일한 요소를 반환합니다. 반환할 요소가 없는 경우 기본값을 반환합니다. 반환할 요소가 두 개 이상 있는 경우 InvalidOperationException을 throw합니다.  

 

프로젝션

시퀀스에서 조건을 충족하는 요소가 일부인지 전체인지를 나타내는 Boolean 값을 반환

Select,  SelectMany, Zip
List<Student> students = new List<Student>
{
    new Student{grade = 3, name = "Tom", scores = new int[] {60, 80} },     
    new Student{grade = 3, name = "Brian" , scores = new int[] {50, 70} },  
    new Student{grade = 4, name = "Chris" , scores = new int[] {80, 80}},   
    new Student{grade = 5, name = "James" , scores = new int[] {100, 100} },
};
        
List<Teacher> teachers = new List<Teacher>
{
    new Teacher{grade = 3, name = "Miss Christina" },
    new Teacher{grade = 4, name = "Mr. Tayler" },
    new Teacher{grade = 6, name = "Mr. Jone" },
    new Teacher{grade = 5, name = "James" },
};        
        
// 익명타입(새로운 형식)으로 표현
var select = students.Select(std => std);
foreach(var sel in select)
{
    Console.WriteLine(sel.grade + "," + sel.name + "," + sel.scores.Max());
}
/*
3,Tom,80
3,Brain,70
4,Chris,80
5,James,100
*/

// 익명타입(새로운 형식)으로 표현 (이름 앞자만 표현)
var selectNew = students.Select(std => new { grd = std.grade, nm = std.name.Substring(0,1), max = std.scores.Max() });
foreach (var sel in selectNew)
{
    Console.WriteLine(sel.grd + "," + sel.nm + "," + sel.max);
}
/*
3,T,80
3,B,70
4,C,80
5,J,100
*/



var selectMany = students.SelectMany((student, index) => student.scores.Select(score => index + ">" + score) );
foreach (var sel in selectMany)
{
    Console.WriteLine(sel);
}
/*
0>60
0>80
1>50
1>70
2>80
2>80
3>100
3>100
*/

var selectmanyQuery = from student in students
                        from score in student.scores
                        select new { score, student };
foreach (var sel in selectmanyQuery)
{
    Console.WriteLine(sel.score + ">" + sel.student.name);
}
/*
60>Tom
80>Tom
50>Brain
70>Brain
80>Chris
80>Chris
100>James
100>James
*/

// select 방법으로 selectMany와 동일하게 표현
var selectby = students.Select((student) => student.scores);
foreach (var sel in selectby)
{
    foreach (var score in sel)
    {
        Console.WriteLine(score);
    }
}


// 두요소를 순서대로 결합
var zip = teachers.Zip(students, (first, second) => new { first.grade, first.name, student = second.name });
foreach (var sel in zip)
{
    Console.WriteLine(sel.grade + ", " + sel.name + ", " + sel.student);
}
/*
3, Miss Christina, Tom
4, Mr. Tayler, Brain
6, Mr. Jone, Chris
5, James, James
*/

 

요소

시퀀스에서 특정 단일 요소를 반환

ElementAtElementAtOrDefault, First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault
List<Student> emptyStudents = new List<Student>();

List<Student> students = new List<Student>
{
    new Student{grade = 3, name = "Tom", scores = new int[] {60, 80} },     
    new Student{grade = 3, name = "Brian" , scores = new int[] {50, 70} },  
    new Student{grade = 4, name = "Chris" , scores = new int[] {80, 80}},   
    new Student{grade = 5, name = "James" , scores = new int[] {100, 100} },
};


var elementAt = students.ElementAt(1).name;	/* Brian  */
var elementAtException = students.ElementAt(5);    // Elenemt가 없으면 ArgumentOutOfRangeException  예외 발생
var elementAtNull = students.ElementAtOrDefault(5); // Elenemt가 없으면 null 반환

var first = students.First().name;	/* Tom  */
var last = students.Last().name;	/* James  */

var firstDefault = emptyStudents.FirstOrDefault();		// null 반환
var lastDefault = emptyStudents.LastOrDefault();		// null 반환

var singleEmpty = emptyStudents.Single();   // 비어있는 요소 반환시 System.InvalidOperationException: 'Sequence contains more than one element'
var single = students.Single();             // 2개 이상 요소 반환시 System.InvalidOperationException: 'Sequence contains more than one element'

var singleDefaultEmpty = emptyStudents.SingleOrDefault();        // 비어있는요소는 null 을 반환
var singleDefault = students.SingleOrDefault( student=> student.grade==3);      // 2개 이상 요소 반환시 System.InvalidOperationException: 'Sequence contains more than one element'

 

 

참고

https://learn.microsoft.com/ko-kr/dotnet/csharp/programming-guide/concepts/linq/projection-operations

https://learn.microsoft.com/ko-kr/dotnet/csharp/programming-guide/concepts/linq/element-operations

반응형