반응형
집합, 분할, 연결 관련한 컬렉션 메소드 에 대해 알아봅니다.
메서드
메서드 이름 | 설명 | C# 쿼리 식 구문 |
Distinct | 컬렉션에서 중복 값을 제거합니다. | |
Except | 두 번째 컬렉션에 표시되지 않는 한 컬렉션의 요소를 의미하는 차집합을 반환 | |
Intersect | 두 컬렉션에 각각 표시되는 요소를 의미하는 교집합을 반환합니다. | |
Union | 두 컬렉션 중 하나에 표시되는 고유한 요소를 의미하는 합집합을 반환합니다. | |
Concat | 두 시퀀스를 연결하여 하나의 시퀀스를 구성 | |
Skip | 시퀀스에서 지정한 위치까지 요소를 건너뜁니다. | |
SkipLast | 시퀀스에서 뒤에서 지정한 위치까지 요소를 건너뜁니다. | |
SkipWhile | 요소가 조건을 충족하지 않을 때까지 조건자 함수를 기반으로 하여 요소를 건너뜁니다. | |
Take | 시퀀스에서 지정된 위치까지 요소를 사용합니다. | |
TakeLast | 시퀀스에서 뒤에서 지정된 위치까지 요소를 사용합니다. | |
TakeWhile | 요소가 조건을 충족하지 않을 때까지 조건자 함수를 기반으로 하여 요소를 사용합니다. |
집합
동일 컬렉션이나 별개 컬렉션(또는 집합)에 동등한 요소가 있는지 여부에 따라 결과 집합을 생성
Distinct, Except, Intersect, Union
int[] scores = { 80, 60, 70, 40, 70, 100, 70 };
int[] scores2 = { 70, 100 };
// 중복제거
var distinct = scores.Distinct();
// 차집합
var except = scores.Except(scores2);
// 교집합
var intersect = scores.Intersect(scores2);
// 합집합
var union = scores.Union(scores2);
사용자 데이터 형식(객체) 중복 제거 방법
* 사용자 지정 데이터 형식의 개체 시퀀스를 비교하려면 클래스에서 IEquatable<T> 제네릭 인터페이스를 구현해야 합니다. 아래는 IEquatable<T> 를 구현한 예제입니다.
IEquatable<T> 상속받아서 Equals, GetHashCode 를 재정의합니다.
class Student : IEquatable<Student>
{
public int grade; //학년
public string name; //이름
public bool Equals(Student other)
{
if (other is null)
return false;
return this.grade == other.grade && this.name == other.name;
}
public override bool Equals(object obj) => Equals(obj as Student);
public override int GetHashCode() => (grade, name).GetHashCode();
}
사용예
List<Student> students = new List<Student>
{
new Student{grade = 3, name = "Tom" },
new Student{grade = 3, name = "Brian" },
new Student{grade = 4, name = "Chris" },
new Student{grade = 5, name = "James" },
new Student{grade = 5, name = "James" },
};
List<Student> students2 = new List<Student>
{
new Student{grade = 3, name = "Tom" },
new Student{grade = 4, name = "Chris" },
new Student{grade = 6, name = "Erick" },
};
Console.WriteLine("== Distinct ==");
foreach (var student in students.Distinct())
{
Console.WriteLine(student.grade + ", " + student.name);
}
/*
3, Tom
3, Brian
4, Chris
5, James
*/
Console.WriteLine("== Except ==");
foreach (var student in students.Except(students2))
{
Console.WriteLine(student.grade + ", " + student.name);
}
/*
3, Brian
5, James
*/
Console.WriteLine("== Intersect ==");
foreach (var student in students.Intersect(students2))
{
Console.WriteLine(student.grade + ", " + student.name);
}
/*
3, Tom
4, Chris
*/
Console.WriteLine("== Union ==");
foreach (var student in students.Union(students2))
{
Console.WriteLine(student.grade + ", " + student.name);
}
/*
3, Tom
3, Brian
4, Chris
5, James
6, Erick
*/
예제에서 Except<T> 를 호출하면 James 중복이 제거된 후 응답하는 것처럼
IEquatabl<T> 를 상속받아서 구현된 객체는 비교 연산을 수행하는 메소드 호출시 중복데이터는 제거된다.
연결
연결은 한 시퀀스를 다른 시퀀스에 추가하는 작업을 나타냅니다.
Concat
Console.WriteLine("== Concat ==");
foreach (var student in students.Concat(students2))
{
Console.WriteLine(student.grade + ", " + student.name);
}
/*
3, Tom
3, Brian
4, Chris
5, James
5, James
3, Tom
4, Chris
6, Erick
*/
* Union 은 집합연산시 중복을 제거하지만 Concat은 두 객체를 연결한다.
분할
입력 시퀀스를 두 개의 섹션으로 나누는 작업
시퀀스 요소들에서 특정 갯수만 가져오거나 할때 유용하다.
Skip, SkipWhile, Take, TakeWhile
List<Student> students = new List<Student>
{
new Student{grade = 3, name = "Tom" },
new Student{grade = 3, name = "Brian" },
new Student{grade = 4, name = "Chris" },
new Student{grade = 5, name = "James" },
new Student{grade = 5, name = "James" },
};
Console.WriteLine("== Skip ==");
foreach (var student in students.Skip(3))
{
Console.WriteLine(student.grade + ", " + student.name);
}
/*
5, James
5, James
*/
Console.WriteLine("== SkipLast ==");
foreach (var student in students.SkipLast(2))
{
Console.WriteLine(student.grade + ", " + student.name);
}
/*
3, Tom
3, Brain
4, Chris
*/
Console.WriteLine("== SkipWhile ==");
foreach (var student in students.SkipWhile(st => st.grade == 3)) //grade == 3 이면 건너뜀
{
Console.WriteLine(student.grade + ", " + student.name);
}
/*
4, Chris
5, James
5, James
*/
Console.WriteLine("== Take ==");
foreach (var student in students.Take(3))
{
Console.WriteLine(student.grade + ", " + student.name);
}
/*
3, Tom
3, Brain
4, Chris
*/
Console.WriteLine("== TakeLast ==");
foreach (var student in students.TakeLast(2))
{
Console.WriteLine(student.grade + ", " + student.name);
}
/*
5, James
5, James
*/
Console.WriteLine("== TakeWhile ==");
foreach (var student in students.TakeWhile(x=> x.grade==3)) //grade == 3 인 경우만 가져옴
{
Console.WriteLine(student.grade + ", " + student.name);
}
/*
3, Tom
3, Brain
*/
참고
https://learn.microsoft.com/ko-kr/dotnet/csharp/programming-guide/concepts/linq/set-operations
반응형