티스토리 뷰
목차
C# Tuple 튜플의 개념(클래스)과 사용 예제 7개 (List, var, string 응용)
C# Tuple
고양이 한 마리가 방 안으로 들어옵니다. 이 고양이의 털은 노랗고, 부드럽습니다. 튜플은 이런 정보를 모두 저장할 수 있는 클래스입니다. 튜플의 인스턴스들은 변경할 수 없는(immutable) 고정 항목을 갖습니다. 그리고 Tuple의 타입은 Class라는 것을 잊지 마세요.
아래 예제에선 3개의 아이템을 갖는 튜플을 선합니다. 그리고, 아이템 1, 2, 3의 속성을 읽습니다. 변경하진 않습니다. (못합니다)
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 | using System; class Program { static void Main() { // Create three-item tuple. Tuple<int, string, bool> tuple = new Tuple<int, string, bool>(1, "cat", true); // Access tuple properties. if (tuple.Item1 == 1) { Console.WriteLine(tuple.Item1); } if (tuple.Item2 == "dog") { Console.WriteLine(tuple.Item2); } if (tuple.Item3) { Console.WriteLine(tuple.Item3); } } } == Output 1 2 3 4 | cs |
C# Tuple Item Types
튜플 내부에 서로 다른 타입들을 선언할 수 있습니다. 예를 들어, double, byte, char 요소들은 이렇게 하나의 튜플로 묶을 수 있습니다. (Tuple<double, byte, char> )
Note: 예를 들어 int value 타입과 string 참조 타입을 함께 사용할 수 있습니다.
4 items. 배열을 보유하는 더 복잡한 튜플도 선언할 수 있으며, 이에 따라 또 다른 메소드로 튜플을 이용합니다.
아래: 이 예제는 튜플이 갖는 4개의 아이템 중 하나는 string 배열, 또 하나는 int 배열입니다.
아래 예제에선 Tuple 생성자를 호출할 때, 배열들을 초기화합니다. 근데 var 키워드를 왜 사용할까요? 문법을 더 예쁘고 짧게 만들어주기 때문입니다.
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 | using System; class Program { static void Main() { // Create four-item tuple. // ... Use var implicit type. var tuple = new Tuple<string, string[], int, int[]>( "perl", new string[] { "java", "c#" }, 1, new int[] { 2, 3 }); // Pass tuple as argument. M(tuple); } static void M(Tuple<string, string[], int, int[]> tuple) { // Evaluate the tuple's items. Console.WriteLine(tuple.Item1); foreach (string value in tuple.Item2) { Console.WriteLine(value); } Console.WriteLine(tuple.Item3); foreach (int value in tuple.Item4) { Console.WriteLine(value); } } } == perl java c# 1 2 3 | cs |
C# 튜플, Sixtuple
6개의 파라미터 리스트를 선언하고 초기화하여 사용합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | using System; class Program { static void Main() { var sixtuple = new Tuple<int, int, int, string, string, string>(1, 1, 2, "dot", "net", "perls"); Console.WriteLine(sixtuple); } } == (1, 1, 2, dot, net, perls) | cs |
Visual Studio에서, 마우스를 var 키워드 위에 올리면 var는 Represents a 6-tuple, or sextuple.이라는 설명과 함께 타입들을 설명합니다. (역주, 전 2015 사용 중인데 안 됩니다. 보여지는 조건이 따로 있을까요?)
[닷넷프레임워크 프로그래밍]
Note: 튜플의 이름은 대부분 프로그램에서 중요하진 않습니다. 그러나 간단한 아래의 간단한 용어들은 경우에 따라 유용할 수도 있습니다.
Names:
A 2-tuple is called a pair.
A 3-tuple is called a triple.
A 4-tuple is called a quadruple.
A 5-tuple is called a quintuple.
A 6-tuple is called a sextuple.
A 7-tuple is called a septuple.
Larger tuples are called n-tuples.
C# Tuple.Create
Invoke 메소드로 예제에선 3개의 인자를 사용합니다(string, int, bool). 결과, Create() 함수는 Tuple<string, int, bool> 형태의 클래스를 리턴합니다.
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 | using System; class Program { static void Main() { // Use Tuple.Create static method. var tuple = Tuple.Create("cat", 2, true); // Test value of string. string value = tuple.Item1; if (value == "cat") { Console.WriteLine(true); } // Test Item2 and Item3. Console.WriteLine(tuple.Item2 == 10); Console.WriteLine(!tuple.Item3); // Write string representation. Console.WriteLine(tuple); } } == True False False (cat, 2, True) | cs |
Internals. instance를 리턴하는 함수(또는 알고리즘) 중 Tuple.Create() (생성자)보다 더 나은 알고리즘은 없습니다. 그러나, 아래 코드에선 Tuple.Create를 호출하지 않으나, 더 나아 보입니다.
1 2 3 4 | public static Tuple<T1> Create<T1>(T1 item1) { return new Tuple<T1>(item1); } | cs |
C# Class implementation
Tuple은 구조체가 아니라 클래스입니다. managed 힙에 할당되기에 각각의 인스턴스들은 가비지 콜렉터가 관리해야 할 항목으로 추가됩니다.
Note: 아이템1, 아이템2, 아이템n... 속성들은 setter가 없습니다. 우리는 튜플 속성이 메모리에 할당되면 변경할 수 없습니다.
[닷넷프레임워크 프로그래밍]
Read-only. 튜플의 생성자를 호출할 땐, 반드시 튜플 내의 모든 값을 초기화해야 합니다. 생성자가 실행되어 메모리에 할당되면 더는 속성을 변경할 수 없습니다. 이 점을 간과하면, 많은 변경 사항이 유발되어 유지 보수 사항이 늘어납니다. 성능 하락에 영향을 미칠 수도 있습니다.
1 2 | Property or indexer 'System.Tuple...Item1' cannot be assigned to--it is read-only. | cs |
Performance
C# KeyValuePair를 이용해 비교한 결과, 객체를 많이 생성한 경우엔 KeyValuePair, 함수 호출(전달)의 경우엔 Tuple이 더 빠릅니다. Tuple을 인자로 넘길 땐 4바이트씩 복사하지만, KeyValuePair는 구조체 등 더 많은 바이트를 복사합니다.
Sort
튜플도 정렬이 됩니다. 데이터 캡슐화를 위한 좋은 방법이죠. 그러나 정렬 기능 구현이 어렵고, 비교 기능을 가진 delegate가 필요합니다.
First: 아래 예제에선 List를 생성하고 그 안에 튜플 객체 3개를 추가합니다. 그리고 List의 Sort 함수를 호출합니다.
Here: 람다를 이용하여 함수 인자(a, b)에 대한 결과값을 Item2의 속성으로 전달합니다.
Tip1: a와 b를 뒤집어 사용해도 됩니다. (결과 같음)
Tip2: 튜플을 정렬할 다른 방법도 있죠. LINQ의 쿼리 문법도 좋은 방법입니다.
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 | using System; using System.Collections.Generic; class Program { static void Main() { List<Tuple<int, string>> list = new List<Tuple<int, string>>(); list.Add(new Tuple<int, string>(1, "cat")); list.Add(new Tuple<int, string>(100, "apple")); list.Add(new Tuple<int, string>(2, "zebra")); // Use Sort method with Comparison delegate. // ... Has two parameters; return comparison of Item2 on each. list.Sort((a, b) => a.Item2.CompareTo(b.Item2)); foreach (var element in list) { Console.WriteLine(element); } } } == (100, apple) (1, cat) (2, zebra) | cs |
Return multiple values
오래도록 C# 문제점으로 지적되던 것 중 하나입니다. 함수는 여러 인자를 받을 수는 있지만 리턴값(리턴 타입)은 오직 하나뿐이었죠. 그러나 튜플은 (자료형이 다른) 여러 데이터를 리턴합니다. (같은 기능을 클래스로 구현하는 것보다 합리적)
Note: 튜플의 장점 중 하나는 재사용성입니다. 다른 함수를 이용해 더 자유롭게 사용할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | using System; class Program { static Tuple<string, int> NameAndId() { // This method returns multiple values. return new Tuple<string, int>("Gudrun", 673); } static void Main(string[] args) { var result = NameAndId(); string name = result.Item1; int id = result.Item2; // Display the multiple values returned. Console.WriteLine(name); Console.WriteLine(id); } } == Gudrun 673 | cs |
A summary
Tuple은 변경 불가 타입(immutable)이며, 여러 타입의 데이터를 저장할 수 있는 유용한 컨테이너입니다.
[닷넷프레임워크 프로그래밍] 튜플의 또 다른 예
(튜플의 예, 튜플 안에 리스트를 두어 사용)
출처 - https://www.dotnetperls.com/tuple
C# Tuple 튜플의 개념(클래스)과 사용 예제 7개 (List, var, string 응용)