-
[프렉티컬 C#] DictionaryDevelopment/C# 2023. 7. 27. 13:34728x90
HashSet<T> 클래스
- Dictionary<TKey, TValue>와 비슷하지만 키 부분만 저장하고 값은 저장하지 않는다.
- 중복을 허용하지 않는다.
- 요소를 꺼내는 순서는 정해져 있지 않아서 등록한 순서로 나온다는 보장이 없다.
- Add 메서드는 요소가 객체에 추가되면 true를 반환하고 이미 존재하는 경우에는 예외를 발생시키지 않고 false를 반환한다.
Dictionary<TKey, TValue> 제네릭 클랙스
- 해시 테이블이라는 데이터 구조로 만들어진 클래스
- 키와 이 키에 대응하는 값을 여러 개 저장할 수 있는 컬렉션
- 배열이나 리스트와 비교했을 때 키를 사용해 값을 구하므로 속도가 가장 빠르다.
딕셔너리 초기화
var abcDic = new Dictionaray<string, int>() { { "abc", 400 }, { "def", 300 }, { "ghi", 350 }, { "jkl", 500 }, { "mno", 450 }, }; // C# 6.0 이후 var abcDic = new Dictionaray<string, int>() { [ "abc"] = 400 , [ "def"] = 300 , [ "ghi"] = 350 , [ "jkl"] = 500 , [ "mno"] = 450 , };
사용자 정의형 객체를 값으로 지정하기
사원 코드를 키로 설정해 쉽고 빠르게 Employee 객체를 구할 수 있다.
var employeeDict = new Dictionaray<int, Employee> { { 100, new Employee(100, "김순자") }, { 200, new Employee(200, "오달순") }, { 300, new Employee(300, "이아주") }, };
딕션너리 요소 추가
// 1번 employeeDict[200] = new Employee(201, "강지순"); // 2번 employeeDict.Add( 200, new Employee(201, "강지순") );
딕션너리 요소 삭제
Remove 메서드
ContainsKey 메서드
Dictionary<TKey,TValue>에 지정한 키가 포함되어 있는지 여부를 확인합니다.
딕셔너리에 있는 모든 요소 꺼내기
- foreach문 사용
- foreach로 꺼낼 수 있는 요소의 형은 KeyValuepair<TKey, TValue>형이다.
- 요소를 꺼내는 순서는 정해져 있지 않아서 등록한 순서로 나온다는 보장이 없다.
foreach (var item in dict) Console.WriteLine("{0} = {1}", item.Key, item.Value);
딕셔너리에 있는 모든 키 꺼내기
- Keys 속성 사용
- 요소를 꺼내는 순서는 정해져 있지 않아서 등록한 순서로 나온다는 보장이 없다.
foreach (var key in dict.Keys) Console.WriteLine(key);
딕셔너리로 변환
ToDictionary 메서드
- IEnumerable<T>에서 Dictionary<TKey,TValue>을 만든다.
- 배열이나 리스트를 딕셔너리로 변환할 수 있다.
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 */
딕셔너리로부터 다른 딕셔너리 생성
var abcDic = new Dictionaray<string, int>() { [ "abc"] = 400 , [ "def"] = 300 , [ "ghi"] = 350 , [ "jkl"] = 500 , [ "mno"] = 450 , }; var newDic = abcDic.Where(x => x.Value >= 300) .ToDictionaray(a => a.Key, a => a.Value); // 두번째 인수도 필요!
사용자 지정 클래스를 키로 사용하기
- Equals 메서드와 GetHashCode 메서드 오버라이드 해야한다.
‣ 솔직히 이해를 못하겠음 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ 누구 좋은 블로그 있어면 추천 좀 여...
- 오버라이드 안 하면 System.Collections.Generic.KeyNotFoundException 예외 발생한다.
class MonthDay { public int Day { get; private set; } public int Month { get; private set; } public MonthDay(int month, int day) { this.Month = month; this.Day = day; } // Equals, GetHashCode 오버라이드 안하면 예외 발생한다. // MonthDay끼리 비교한다 public override bool Equals(object obj) { var other = obj as MonthDay; if (other == null) throw new ArgumentException(); return this.Day == other.Day && this.Month == other.Month; } // 해시 코드를 구한다 public override int GetHashCode() { return Month.GetHashCode() * 31 + Day.GetHashCode(); } }
var dict = new Dictionary<MonthDay, string> { { new MonthDay(6, 6), "현충일" }, { new MonthDay(8, 15), "광복절" }, { new MonthDay(10, 3), "개천절" }, }; var md = new MonthDay(8, 15); var s = dict[md]; Console.WriteLine(s);
키 중복 허용하기
값의 형을 List<>로 지정한다. ➢ 하나의 키에 여러 값을 지정할 수 있게 된다. ➢ 결과적으로 키가 중복되는 것을 허용하는 것이다.
// 딕셔너리를 초기화한다 var dict = new Dictionary<string, List<string>>() { { "PC", new List<string> { "퍼스널 컴퓨터", "프로그램 카운터", } }, { "CD", new List<string> { "컴팩트 디스크", "캐시 디스펜서", } }, }; // 딕셔너리에 추가한다 var key = "EC"; var value = "전자상거래"; if (dict.ContainsKey(key)) { dict[key].Add(value); } else { dict[key] = new List<string> { value }; } // 딕셔너리의 내용을 열거한다 foreach (var item in dict) { foreach (var term in item.Value) { Console.WriteLine("{0} : {1}", item.Key, term); } } /* [결과] PC : 퍼스널 컴퓨터 PC : 프로그램 카운터 CD : 컴팩트 디스크 CD : 캐시 디스펜서 EC : 전자상거래 */
연습 문제
문제 7.1
static void Main(string[] args) { // 1 var str = "Cozy lummox gives smart squid who asks for job pen"; var str2 = str.Replace(" ", "").ToUpper(); var dic = new Dictionary<char, int>(); foreach (var item in str2) { if (dic.ContainsKey(item)) { dic[item] = ++dic[item]; } else { dic[item] = 1; } } foreach (var item in dic.OrderBy(s => s.Key)) { Console.WriteLine($"'{item.Key}' : {item.Value}"); } // 2 var sortedDic = new SortedDictionary<char, int>(dic); }
리뷰
1. dic[item] = ++dic[item]; 을 dic[item]++; 로 바꾸면 되는데 너무 복잡하게 작성했다.
예제 코드에서 if ('A' <= uc && uc <= 'Z') {} 구문은 꼭 필요했는지 의문이다.
또, var uc = char.ToUpper(c); 코드도 굳이 반복문 안에 들어가야했는지 의문이다.
내 코드가 더 나은 듯?
2. 난 SortedDictionary 클래스 안에 내장되어 있는 Convert 기능 사용했는데 예제는 처음부터 다시 작성했네
차이점 보면 Dictionary는 OrderBy 해줘야하지만 SortedDictionary는 자동 정렬되서 출력된다.
그래서 SortedDictionary 군!
검색해서 나온 Dictionary랑 SortedDictionary 차이점
A SortedDictionary is implemented as a binary search tree. Therefore, accessing an element is O(lg(n)). A Dictionary is a hash table, and has a complexity of O(1) for access.
A SortedDictionary is quite useful when you need the data to be sorted (a Dictionary has no defined order). Dictionary is appropriate for most cases.
예제 코드
class Program { static void Main(string[] args) { var text = "Cozy lummox gives smart squid who asks for job pen"; Exercise1_1(text); Console.WriteLine(); Exercise1_2(text); } static void Exercise1_1(string text) { var dict = new Dictionary<Char, int>(); foreach (var c in text) { var uc = char.ToUpper(c); if ('A' <= uc && uc <= 'Z') { if (dict.ContainsKey(uc)) dict[uc]++; else dict[uc] = 1; } } foreach (var item in dict.OrderBy(x => x.Key)) Console.WriteLine("{0}:{1}", item.Key, item.Value); } static void Exercise1_2(string text) { var dict = new SortedDictionary<Char, int>(); foreach (var c in text) { var uc = char.ToUpper(c); if ('A' <= uc && uc <= 'Z') { if (dict.ContainsKey(uc)) dict[uc]++; else dict[uc] = 1; } } foreach (var item in dict) Console.WriteLine("{0}:{1}", item.Key, item.Value); } }
문제 7.2
class Program { ... // 3번 var canRemove = abbrs.Remove("IOC"); Console.WriteLine(canRemove); var count = abbrs.Count; Console.WriteLine(count); // 4번 abbrs.Find3Char(); ... }
class Abbreviations { ... // 1번 public int Count => _dict.Count; // 2번 public bool Remove(string abbr) { if (_dict.ContainsKey(abbr)) return true; return false; } // 4번 public void Find3Char() { var newDict = _dict.Where(w => w.Key.Count() == 3); foreach (var item in newDict) { Console.WriteLine($"{item.Key}={item.Value}"); } } ... }
리뷰
2. Remove 메서드는 요소를 성공적으로 찾아서 제거한 경우 true이고, 그렇지 않으면 false 반환한다. 괜히 if문으로 이중체크 했네!
4. 길이 구하는 걸 때 습관적으로 Count 메서드 쓴다. 3글자로 된 줄임말을 출력하는거니 글자 길이를 확실하게 나타내는 Length 메서드를 사용하는게 좋을 듯 하다.
What 보다는 How를 생각하자!
예제 코드
class Program { ... // 7.2.3 (Count를 호출한 예) // 위에 나온 Add 메서드에서 두 개의 오브젝트를 추가했으므로 읽어들인 단어 수+2가 Count의 값이 된다 var count = abbrs.Count; Console.WriteLine(abbrs.Count); Console.WriteLine(); // 7.2.3 (Remove를 호출한 예) if (abbrs.Remove("NPT")) Console.WriteLine(abbrs.Count); if (!abbrs.Remove("NPT")) Console.WriteLine("삭제할 수 없습니다."); Console.WriteLine(); // 7.2.4 // IEnumerable<>를 구현했으므로 LINQ를 사용할 수 있다 foreach (var item in abbrs.Where(x => x.Key.Length == 3)) Console.WriteLine("{0}={1}", item.Key, item.Value); ... }
class Abbreviations { ... // 7.2.1 public int Count { get { return _dict.Count; } } // 7.2.2 public bool Remove(string abb) { return _dict.Remove(abb); } ... }
728x90'Development > C#' 카테고리의 다른 글
[프렉티컬 C#] 날짜와 시간 처리 (0) 2023.07.28 [C#] 인덱서 (0) 2023.07.27 [프렉티컬 C#] 배열과 List<T> (0) 2023.07.26 [프렉티컬 C#] 문자열 처리 (0) 2023.07.26 [프렉티컬 C# 연습문제] 2부 - 1장 (0) 2023.07.25