Tuple
여러 개의 개별 값을 이용하여 단일의 복합 값을 나타내는 데이터 구조.
각각의 값이 서로 연관되어 있음에도 새로운 타입을 작성하고 싶지 않다면,
추가적인 캡슐화 작업 없이 간단히 복합 구성을 사용할 수 있다.
🫧
(int, int) t = (0, 1);
// t.ToString();
// Output: (0, 1)
// t.GetHashCode();
(double, int) t = (4.5, 3);
// t.Item1, t.Item2
(double Sum, int) t = (4.5, 3);
// t.Sum(=Item1), t.Item2
(double Sum, int Count) t = (4.5, 3);
// t.Sum(=Item1), t.Count(=Item2)
var t = (4.5, 3);
// t.Item1, t.Item2
var t = (Sum: 4.5, 3);
// t.Sum(=Item1), t.Item2
var t = (Sum: 4.5, Count: 3);
// t.Sum(=Item1), t.Count(=Item2)
(double Sum, int Count) t = (Sum: 4.5, Count: 3);
// t.Sum, t.Count
// CS8123: 튜플 요소 이름 'Sum'은(는) 대상 형식 '(double Sum, int Count)'에서 다른 이름이 지정되었거나 이름이 지정되지 않았기 때문에 무시됩니다.
var sum = 4.5;
var count = 3;
var t = (sum, count);
Console.WriteLine(quot;Sum of {t.count} elements is {t.sum}.");
// Tuple Projection Initializer
// Can't Projection: Tuple's Member Name(ToString, Rest, Item1, Item2...), Already Used
var 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);
// t.Item1 ~ t.Item26
컴파일 시간에 필드 이름을 기본 이름으로 변경
= 명시적 지정, 유추된 필드 이름 런타임 사용 불가능
var xs = new[] { 4, 7, 9 };
var limits = FindMinMax(xs);
Console.WriteLine(quot;Limits of [{string.Join(" ", xs)}] are {limits.min} and {limits.max}");
// Output:
// Limits of [4 7 9] are 4 and 9
var ys = new[] { -9, 0, 67, 100 };
var (minimum, maximum) = FindMinMax(ys);
Console.WriteLine(quot;Limits of [{string.Join(" ", ys)}] are {minimum} and {maximum}");
// Output:
// Limits of [-9 0 67 100] are -9 and 100
(int min, int max) FindMinMax(int[] input)
{
if (input is null || input.Length == 0)
{
throw new ArgumentException("Cannot find minimum and maximum of a null or empty array.");
}
var min = int.MaxValue;
var max = int.MinValue;
foreach (var i in input)
{
if (i < min)
{
min = i;
}
if (i > max)
{
max = i;
}
}
return (min, max);
}
// 할당 및 분해
// 두 튜플 형식의 요소 수가 동일함
// AND
// 각 튜플 위치에서 오른쪽 튜플 요소의 형식이 해당하는 왼쪽 튜플 요소의 형식과 동일하거나 해당 형식으로 암시적으로 변환 가능함
(int, double) t1 = (17, 3.14);
(double First, double Second) t2 = (0.0, 1.0);
t2 = t1;
// t2.First, t2.Second
(double A, double B) t3 = (2.0, 3.0);
t3 = t2;
// t3.A, t3.B
// 필드 이름은 무시되고 할당되지 않음
// t3.First, t3.Second
// = 대입 연산자를 이용한 튜플 인스턴스 개별 변수 분해
// 명시적 선언
var t = ("post office", 3.6);
(string destination, double distance) = t;
(string destination, var distance) = t;
// 괄호밖 var (형식화된 변수를 암시적 선언, 컴파일러가 유추)
var t = ("post office", 3.6);
var (destination, distance) = t;
// 기존 변수 사용
var destination = string.Empty;
var distance = 0.0;
var t = ("post office", 3.6);
(destination, distance) = t;
// 혼합
// 삭제 (무시)
var (_, _, _, a, _, b) = ~
// 튜플 비교
Console.WriteLine((Display(1), Display(2)) == (Display(3), Display(4)));
int Display(int s)
{
Console.WriteLine(s);
return s;
}
// Output:
// 1
// 2
// 3
// 4
// False
// == 및 != 연산자는 단락(short-circuiting) 방식으로 튜플을 비교합니다. 즉, 같지 않은 요소 쌍을 충족하거나 튜플의 끝에 도달하는 즉시 연산이 중지됩니다. 그러나 다음 예제와 같이 비교하기 전에 ‘모든’ 튜플 요소가 평가됩니다.
// Deconstruct
var p = new Person("John", "Quincy", "Adams", "Boston", "MA");
// Deconstruct the person object.
var (fName, lName, city, state) = p;
var (temp, _, _) = p;