LINQ Method 정리
본 글은 공부하며 작성하였습니다. 정보를 얻으실 때 사실과 다르거나 부정확한 정보가 들어있을 수도 있습니다.
LINQ의 Method를 정리한다. 예제는 마이크로소프트 문서 또는 본인 코드.
Aggregate
데이터를 누적하여 집계한다. 원하는 규칙을 정해 데이터를 가공한다고 생각하면 된다.
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
// Determine whether any string in the array is longer than "banana".
string longestName =
fruits.Aggregate("banana",
(longest, next) =>
next.Length > longest.Length ? next : longest,
// Return the final result as an upper case string.
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.
Aggregate(초기값, (인자) => 식) 과 같은 형태다. 물론 Aggregate((인자) => 식)으로도 가능.
예제에서는 "banana"를 초기값으로 두고, fruits의 각 요소마다 반복을 했다. longestName에 가장 긴 string인 "passionfruit"가 반환된다.
All
모든 요소가 특정 조건에 맞는지 확인한다.
Pet[] pets = { new Pet { Name="Barley", Age=10 },
new Pet { Name="Boots", Age=4 },
new Pet { Name="Whiskers", Age=6 } };
// Determine whether all pet names
// in the array start with 'B'.
bool allStartWithB = pets.All(pet =>
pet.Name.StartsWith("B"));
Any
하나라도 조건에 맞는 요소가 있는지 확인한다.
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
bool ContainLength5 = fruits.Any((element) => element.Length == 5);
AsEnumerable
시퀀스를 IEnumerable<T>의 형태로 반환한다.
Average
숫자 값 시퀀스의 평균을 계산한다.
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
var result = fruits.Average(element => element.Length);
int[] numbers = { 2, 5, 10, 200, 30 };
print(numbers.Average()); //prints 49.4
Cast
IEnumerable의 각 요소를 지정된 형식으로 캐스팅한다. 쉽게 말하자면 형식이 없던 것들에게 타입을 지정해주는 것이다.
ArrayList fruits = new ArrayList();
fruits.Add("apple");
fruits.Add("mango");
fruits.Add("orange");
IEnumerable enumerable = fruits.Cast<string>();
형식이 없던 List에 캐스트를 수행하지 않으면, 아래와 같은 foreach문을 돌릴 수 없다.
foreach (string fruit in query)
{
Console.WriteLine(fruit);
}
Concat
두 시퀀스를 연결한다.
Pet[] cats = GetCats();
Pet[] dogs = GetDogs();
IEnumerable<string> query =
cats.Select(cat => cat.Name).Concat(dogs.Select(dog => dog.Name));
Contains
시퀀스에 지정한 요소가 들어 있는지 확인한다.
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
print(fruits.Contains("apple")); //prints true
Count
시퀀스의 수를 반환한다.
string[] fruits = { "apple", "mango", "orange", "passionfruit", "grape" };
var count = fruits.Count(e => e.Contains('p'));
print(count); //prints 3
DefaultIfEmpty
시퀀스가 비어 있으면 기본값을 할당하여 반환한다.
List<string> fruits = new List<string>();
foreach (var fruit in fruits.DefaultIfEmpty("default"))
{
print(fruit);
}
//prints default
List<string> fruits = new List<string>();
fruits.Add("banana");
foreach (var fruit in fruits.DefaultIfEmpty("default"))
{
print(fruit);
}
//prints banana
Distinct
중복된 요소들을 제외한 시퀀스를 반환한다.
string[] fruits = { "apple", "grape", "orange", "apple", "grape" };
foreach (var fruit in fruits.Distinct())
{
print(fruit);
}
//prints following output
//apple
//grape
//orange
ElementAt
지정한 인덱스의 요소를 반환한다. 예제는 굳이 왜 ElementAt을 쓰는 건가 싶지만.
string[] fruits = { "apple", "grape", "orange", "pineapple", "passionfruit" };
int randomIndex = Random.Range(0, fruits.Length);
print(fruits[randomIndex]);
print(fruits.ElementAt(randomIndex));
ElementAtOrDefault
지정한 인덱스의 요소를 반환한다. 만약 인덱스가 범위를 벗어나면 기본값을 반환한다. 아니, 예외처리 코드를 굳이 작성할 필요 없는 이런 갓 메소드가...
string[] fruits = { "apple", "grape", "orange", "pineapple", "passionfruit" };
print(fruits.ElementAtOrDefault(10));
//prints null
Except
두 시퀀스의 차집합을 구한다.
string[] fruitsA = { "apple", "grape", "orange", "pineapple", "passionfruit" };
string[] fruitsB = { "orange", "pineapple", "passionfruit", "banana" };
foreach (var fruit in fruitsA.Except(fruitsB))
{
print(fruit);
}
//prints following output
//apple
//grape
First
시퀀스의 첫번째 요소를 반환한다.
int[] numbers = { 9, 34, 65, 92, 87, 435, 3, 54,
83, 23, 87, 435, 67, 12, 19 };
int first = numbers.First(number => number > 80);
Console.WriteLine(first);
//prints 92
FirstOrDefault
시퀀스의 첫번째 요소를 반환한다. 없으면 기본값을 반환한다.
string[] fruitsA = { "apple", "grape", "orange", "pineapple", "passionfruit" };
print(fruitsA.FirstOrDefault(e => e.Length > 20));
//prints Null
GroupBy
시퀀스의 요소를 그룹화한다.
string[] fruits = { "apple", "grape", "orange", "pineapple", "passionfruit" };
IEnumerable<IGrouping<int, string>> groupFruits = fruits.GroupBy(e => e.Length);
foreach (var group in groupFruits)
{
foreach (var item in group)
{
print($"length {group.Key} : {item}");
}
}
GroupJoin
키가 같은지 여부에 따라 두 시퀀스의 요소를 연관시키고 결과를 그룹화한다.
내용이 길어질 것 같아 다른 포스트로 작성할 예정. (이후 해당 포스트 이곳에 링크)
Intersect
두 시퀀스의 교집합을 구한다.
string[] fruitsA = { "apple", "grape", "orange", "pineapple", "passionfruit" };
string[] fruitsB = { "banana", "pineapple", "mango" };
foreach (var fruit in fruitsA.Intersect(fruitsB))
{
print(fruit);
}
//prints pineapple
Join
두 시퀀스를 하나로 합친다... 라고 말하면 완전히 적절하지는 않은 것 같다. 굳이 표현하자면 DB의 내부 조인이다.
예제가 또 길어지므로 다른 포스트로 분리하겠다. Join/GroupJoin만 따로 다뤄야 할 듯.
Last, LastOrDefault
시퀀스의 마지막 요소를 반환한다. 예제는 First/FirstOrDefault와 거의 동일하므로 생략.
Max
시퀀스의 최대값을 반환한다. 아래 예제는 string 값이 아니라 int 값을 반환한다. 주의.
string[] fruitsA = { "apple", "grape", "orange", "pineapple", "passionfruit" };
print(fruitsA.Max(e => e.Length));
//prints 12
Min
시퀀스의 최소값을 반환한다. Max와 별 차이 없으므로 넘어간다.
OfType
시퀀스에서 지정한 타입만 걸러낸다.
System.Collections.ArrayList fruits = new System.Collections.ArrayList(4);
fruits.Add("Mango");
fruits.Add("Orange");
fruits.Add(3.0);
fruits.Add("Banana");
// Apply OfType() to the ArrayList.
IEnumerable<string> query1 = fruits.OfType<string>();
// This code produces the following output:
//
// Elements of type 'string' are:
// Mango
// Orange
// Banana
OrderBy
시퀀스의 요소를 오름차순으로 정렬한다.
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);
foreach (Pet pet in query)
{
Console.WriteLine("{0} - {1}", pet.Name, pet.Age);
}
OrderByDescending
시퀀스의 요소를 내림차순으로 정렬한다. 생략.
Range
지정된 범위 내의 정수 시퀀스를 생성한다. 와---우.
// 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
반복되는 단일 값이 들어 있는 시퀀스를 생성한다.
IEnumerable<string> strings =
Enumerable.Repeat("I like programming.", 8);
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.
*/
Reverse
시퀀스의 요소 순서를 반전한다. 명확한 설명이므로 굳이 예제는 안 가져 왔음.
Select
시퀀스의 각 요소를 가져와서 입맛대로 가공한다.
string[] fruitsA = { "apple", "grape", "orange", "pineapple", "passionfruit" };
var result = fruitsA.Select((e, index) => $"[Index = {index} / {e}]" );
foreach (var item in result)
{
print(item);
}
SelectMany
Select가 하나의 시퀀스에서 값을 가공한다면, SelectMany는 다중 시퀀스에서 값을 가공한다고 생각하면 된다.
string[] fruitsA = { "apple", "grape" };
int[] fruitsB = { 0, 1, 2, 3 };
var result = fruitsA.SelectMany(fruitA => fruitsB, (a, b) => new { a, b });
foreach (var item in result)
{
print($"{item.a}, {item.b}");
}
//prints following output
//apple, 0
//apple, 1
//apple, 2
//apple, 3
//grape, 0
//grape, 1
//grape, 2
//grape, 3
예제는 fruitsA와 fruitsB에서 값을 가져와 가공하는 모습을 보여주고 있다.
SequenceEqual
두 시퀀스의 요소가 같은지 확인한다.
Pet pet1 = new Pet { Name = "Turbo", Age = 2 };
Pet pet2 = new Pet { Name = "Peanut", Age = 8 };
// Create two lists of pets.
List<Pet> pets1 = new List<Pet> { pet1, pet2 };
List<Pet> pets2 = new List<Pet> { pet1, pet2 };
bool equal = pets1.SequenceEqual(pets2);
Single
시퀀스의 특정 단일 요소를 반환한다. 조건에 맞는 요소가 둘 이상이면 예외가 발생한다.
string[] fruits = { "apple", "banana", "mango",
"orange", "passionfruit", "grape" };
string fruit1 = fruits.Single(fruit => fruit.Length > 10);
Console.WriteLine(fruit1);
//prints passionfruit
SingleOrDefault
Single인데, 특정 단일 요소가 존재하지 않으면 기본값을 반환한다. 생략.
Skip
시퀀스에서 지정된 수의 요소를 건너뛴 다음 나머지 요소를 반환한다. 다른 LinQ 메소드랑 같이 쓰는 방식이다.
string[] fruitsA = { "apple", "grape", "orange", "pineapple", "passionfruit" };
var result = fruitsA.Where((e) => e.Length > 4).Skip(3);
foreach (var item in result)
{
print(item);
}
//prints following output
//pineapple
//passionfruit
SkipLast
Skip이 앞에서부터 건너뛰었다면, SkipLast는 뒤에서부터 지정된 수만큼 없애는 방식.
SkipWhile
지정된 조건이 true인 동안은 skip한다.
string[] fruitsA = { "apple", "grape", "orange", "pineapple", "passionfruit", "fry" };
var result = fruitsA.SkipWhile((e) => e.Length < 6);
foreach (var item in result)
{
print(item);
}
//prints following output
//orange
//pineapple
//passionfruit
//fry
Sum
숫자 값 시퀀스의 합을 계산한다. 생략.
Take
시퀀스 앞부터 지정된 개수만큼만 반환한다. 3을 인자로 주면, 앞에서부터 3개만 가져온다.
string[] fruitsA = { "apple", "grape", "orange", "pineapple", "passionfruit", "fry" };
var result = fruitsA.Take(2);
foreach (var item in result)
{
print(item);
}
//prints following output
//apple
//grape
TakeLast
시퀀스 뒤부터 지정된 개수만큼만 반환한다.
TakeWhile
지정된 조건이 true인 동안 시퀀스의 요소를 반환한다.
string[] fruitsA = { "apple", "grape", "orange", "pineapple", "passionfruit", "fruit" };
var result = fruitsA.TakeWhile((e) => e.Length == 5);
foreach (var item in result)
{
print(item);
}
//prints following output
//apple
//grape
ThenBy
시퀀스의 요소를 정렬했던 걸 다시 오름차순으로 정렬한다. ...예제를 보자.
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);
foreach (string fruit in query)
{
Console.WriteLine(fruit);
}
/*
This code produces the following output:
apple
grape
mango
banana
orange
blueberry
raspberry
passionfruit
*/
fruits를 길이 순으로 정렬한 뒤에, 알파벳 순으로 재정렬하였다.
ThenByDescending
시퀀스의 요소를 정렬했던 걸 다시 내림차순으로 정렬한다.
ToArray
배열 형태로 변환한다.
ToDictionary
딕셔너리 형태로 변환한ㄷ.... 뭐라고?
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
*/
아이고 자동으로 키를 뽑아내는 줄 알고 놀랐지 않은가 ^^ 키는 내가 지정해주는 거였다.
ToHashSet
HashSet 형태로 변환한다.
ToList
List 형태로 변환한다.
ToLookup
Lookup 형태로 변환한다. 이 자료형은 처음 본다.
Union
두 시퀀스의 합집합을 구한다. 생략.
Where
조건자에 따라 값의 시퀀스를 필터링한다. 가장 자주 쓰는 LinQ 메서드가 되지 않을까 싶다.
List<string> fruits =
new List<string> { "apple", "passionfruit", "banana", "mango",
"orange", "blueberry", "grape", "strawberry" };
IEnumerable<string> query = fruits.Where(fruit => fruit.Length < 6);
foreach (string fruit in query)
{
Console.WriteLine(fruit);
}
/*
This code produces the following output:
apple
mango
grape
*/
Zip
지정된 함수를 두 시퀀스의 해당 요소에 적용하여 결과 시퀀스를 만든다.
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);
foreach (var item in numbersAndWords)
Console.WriteLine(item);
// This code produces the following output:
// 1 one
// 2 two
// 3 three
'프로그래밍 > C#' 카테고리의 다른 글
Enum.ToString 최적화하기 (0) | 2022.02.25 |
---|---|
[.Net C# 설명서] 읽고 정리하기 (0) | 2021.09.29 |
[C# 코딩의 기술]에서 얻은 지식들 (0) | 2021.09.24 |
C# 연산자 오버로딩 : ==, Equals에서 null값 판단하기 (0) | 2021.03.24 |
C# Closure : for문의 변수를 람다식에서 참조하면 슬퍼지는 이유 (2) | 2019.07.29 |
댓글
이 글 공유하기
다른 글
-
[.Net C# 설명서] 읽고 정리하기
[.Net C# 설명서] 읽고 정리하기
2021.09.29 -
[C# 코딩의 기술]에서 얻은 지식들
[C# 코딩의 기술]에서 얻은 지식들
2021.09.24 -
C# 연산자 오버로딩 : ==, Equals에서 null값 판단하기
C# 연산자 오버로딩 : ==, Equals에서 null값 판단하기
2021.03.24 -
C# Closure : for문의 변수를 람다식에서 참조하면 슬퍼지는 이유
C# Closure : for문의 변수를 람다식에서 참조하면 슬퍼지는 이유
2019.07.29