IT/언어

[C#] C#의 Dictionary (사전형) 데이터 사용법

개발자 두더지 2021. 3. 6. 01:05
728x90

Dictionary이란


 Dictionary에서는 Key라고 불리는 인덱스 번호를 대신해 사용하는 명칭과 Value라고 불리는 값을 세트로 다룬다.  참고로 Key와 Vlaue 세트로 다루는 배열을 "연관 배열"이라고 부른다. 

 C#에서 연관 배열을 다루기 위한 클래스가 Dictionary클래스이다. Dictionary클래스에서는 Key를 사용하여 Value의 값을 취득한다. 덧붙여 중복된 Key을 사용할 수 없으므로 주의하자!

 

 

List와의 차이점


 List는 인덱스 번호를 사용하여 요소의 값을 얻는다. 그에 반해 Dictionary는 앖서 말했는 Key값을 사용하여 Value를 취득하므로, 숫자이외의 문자열 등을 키로 지정하여 세트의 값을 뽑아낼 수 있다. 항목과 그 값이 세트 데이터로 다루어질 필요가 있는 경우에 사전형을 이용한다. 

 

 

Dictionary의 선언, 정의, 초기화


  선언, 정의는 아래와 같이 한다.

Dictionary<Key데이터형, Value데이터형> 오브젝트명 = new Dictionary<Key데이터형, Value데이터형>()

 Dictionary 클래스를 사용하기 위해서는 using을 사용하여 System.Collections.Generic클래스를 호출해둘 필요가 있다. 또한 아래와 같이 작성하는 것도 가능하다.

var 오브젝트명 = new Dictionary<Key데이터형, Value데이터형>()

 구체적으로 예시를 들자면 아래와 같다.

var a = new Dictionary<string,string>();

 위 코드는 Dictionary 클래스를 인스턴스화하여 변수a에 대입하고 있는 코드이다. 이 변수 a는 복수의 키와 값을 같게 된다. "<>"는 제네릭 클래스이다. var 키워드를 사용하고 있어 타입 추론이 이루어진다. 변수 a의 각 키와 값의 데이터 형은 string과 string이다. 

 선언과 정의 그리고 초기화를 동시에 하는 것도 가능하다.

var 오브젝트명 = new Dictionary<Key데이터형, Value데이터형>()
    {
        {Key0, Value0},
        {Key1, Value1},
        ・・・・・・
    };

 

 

Add로 요소를 추가하기


요소를 추가하기 위해서는 Add메소드를 사용한다. Add메소드는 아래와 같이 정의되어 있다.

public void Add(
    TKey key,
    TValue value
)

인수 key에는 추가요소의 키를, 인수 value에서는 추가 요소의 값을 지정하다.

샘플 코드를 확인해보자.

using System;
using System.Collections.Generic;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var myTable = new Dictionary<string, string>();
      myTable.Add("Hokkaido", "Sapporo");
      myTable.Add("Iwate", "Morioka");
      myTable.Add("Miyagi", "Sendai");
    }
  }
}

 

 

foreach로 요소를 취득하는 방법


foreach로 요소의 취득하는 방법을 소개하고자 한다. 

Key와 Value 양쪽을 취득하는 방법

KeyValuePair구조체를 사용하여, Key와 Value를 모두 얻을 수 있다. 샘플 코드는 다음과 같다.

using System;
using System.Collections.Generic;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var myTable = new Dictionary<string, string>();
      myTable.Add("Hokkaido", "Sapporo");
      myTable.Add("Iwate", "Morioka");
      myTable.Add("Miyagi", "Sendai");
      
      foreach(KeyValuePair<string, string> item in myTable) {
        Console.WriteLine("[{0}:{1}]", item.Key, item.Value);  
      }
      
      Console.ReadKey();
    }
  }
}

실행결과

[Hokkaido:Sapporo]
[Iwate:Morioka]
[Miyagi:Sendai]

 

Key만을 취득하는 방법

Dictionary로 부터 Key값만을 얻고 싶은 경우에는 Keys 속성을 사용한다.

using System;
using System.Collections.Generic;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var myTable = new Dictionary<string, string>();
      myTable.Add("Hokkaido", "Sapporo");
      myTable.Add("Iwate", "Morioka");
      myTable.Add("Miyagi", "Sendai");
      
      foreach(string Key in myTable.Keys) {
        Console.WriteLine(Key);  
      }
      
      Console.ReadKey();
    }
  }
}

실행결과

Hokkaido
Iwate
Miyagi

Value만을 취득하는 방법

Dictionary로 부터 Value값만을 얻고 싶은 경우에는 Values 속성을 사용한다.

using System;
using System.Collections.Generic;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var myTable = new Dictionary<string, string>();
      myTable.Add("Hokkaido", "Sapporo");
      myTable.Add("Iwate", "Morioka");
      myTable.Add("Miyagi", "Sendai");
      
      foreach(string Value in myTable.Values) {
        Console.WriteLine(Value);  
      }
      
      Console.ReadKey();
    }
  }
}

실행결과

Sapporo
Morioka
Sendai

 

 

Key로 Value를 취득하는 방법


Dictionary의 특성은 인덱스 번호가 아닌, Key가 되는 문자열 등으로도 Value의 값을 얻을 수 있다는 것이다. 샘플 코드는 다음괕 같다.

using System;
using System.Collections.Generic;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var myTable = new Dictionary<string, string>();
      myTable.Add("Hokkaido", "Sapporo");
      myTable.Add("Iwate", "Morioka");
      myTable.Add("Miyagi", "Sendai");
      
      string str = "Iwate";
      Console.WriteLine("[{0}:{1}]", str, myTable[str]);  
      
      Console.ReadKey();
    }
  }
}

실행결과

[Iwate:Morioka]

 

 

복사하는 방법


Dictionary의 오브젝트를 복사하고 싶은 경우가 있을 것이다. 이러한 경우에는 복사 대상 오브젝트를 선언, 정의할 때에 생성자 인수에 원본 오브젝트를 지정하면 복사가 완료된다.

샘플 코드를 확인하자면 다음과 같다.

using System;
using System.Collections.Generic;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var myTable1 = new Dictionary<string, string>();
      myTable1.Add("Hokkaido", "Sapporo");
      myTable1.Add("Iwate", "Morioka");
      myTable1.Add("Miyagi", "Sendai");
      
      // 생성자 인수에 원본의 객체를 지정
      var myTable2 = new Dictionary<string, string>(myTable1);
      
      foreach(KeyValuePair<string, string> item in myTable2) {
        Console.WriteLine("[{0}:{1}]", item.Key, item.Value);  
      }
      
      Console.ReadKey();
    }
  }
}

실행결과

[Hokkaido:Sapporo]
[Iwate:Morioka]
[Miyagi:Sendai]

 

 

요소를 검색하는 방법


Dictionary의 요소의 Key 혹은 Value에 지정한 값이 포함되어 있는지 검색하는 것도 가능하다. Key를 검색할 경우, Value를 검색할 경우 각각 나눠서 살펴보자.

Key를 검색하는 방법

ContainsKey메소드를 사용한다. ContainsKey메소드는 아래와 같이 정의되어 있다.

public bool ContainsKey(
    TKey key
)

샘플코드를 확인해보자.

using System;
using System.Collections.Generic;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var myTable = new Dictionary<string, string>();
      myTable.Add("Hokkaido", "Sapporo");
      myTable.Add("Iwate", "Morioka");
      myTable.Add("Miyagi", "Sendai");
      
      string str = "Iwate";
      if(myTable.ContainsKey(str)) {
        Console.WriteLine("{0}은(는) 이미 Key로 사용되고 있습니다.", str);
      } else {
        Console.WriteLine("{0}은(는) Key로 사용되지 않고 있습니다.", str);
      }
      
      Console.ReadKey();
    }
  }
}

실행결과

Iwate은(는) 이미 Key로 사용되고 있습니다.

Value를 검색하는 방법

ContainsValue 메소드를 사용한다. ContainsValue 메소드는 아래와 같이 정의되어 있다.

public bool ContainsValue(
    TValue value
)

샘플 코드로 확인해보자.

using System;
using System.Collections.Generic;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var myTable = new Dictionary<string, string>();
      myTable.Add("Hokkaido", "Sapporo");
      myTable.Add("Iwate", "Morioka");
      myTable.Add("Miyagi", "Sendai");
      
      string str = "Sendai";
      if(myTable.ContainsValue(str)) {
        Console.WriteLine("{0}은(는) 이미 Value에 존재하고 있습니다.", str);
      } else {
        Console.WriteLine("{0}은(는) Value에 존재하지 않는 값입니다.", str);
      }
      
      Console.ReadKey();
    }
  }
}

실행결과

Sendai은(는) 이미 Value에 존재하고 있습니다.

 

 

요소를 정렬하는 방법


Dictionary의 요소를 정렬하기 위한 방법은 여러가지 존재한다. LINQ의 OrderBy메소드를 사용할 수도 있고, KeyValuePair구조체의 List를 사용하는 방법 등이 있다.

LINQ를 사용하는 방법

LINQ의 OrderBy메소드를 사용하여, 그 인수로 람다식을 작성하면 간단하게 정렬할 수 있다.

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var myTable = new Dictionary<string, string>();
      myTable.Add("Hokkaido", "Sapporo");
      myTable.Add("Iwate", "Morioka");
      myTable.Add("Miyagi", "Sendai");
      
      var newTable = myTable.OrderBy(x => x.Value);
      
      foreach(KeyValuePair<string, string> item in newTable) {
        Console.WriteLine("[{0}:{1}]", item.Key, item.Value);  
      }
      
      Console.ReadKey();
    }
  }
}

실행결과

[Iwate:Morioka]
[Hokkaido:Sapporo]
[Miyagi:Sendai]

이 샘플 코드에서는 Dictionary 오브젝트 myTable의 Value의 요소를 기준으로 오름차순 정렬하고 있다. LINQ의 OrderBy 메소드를 사용하여 정렬하고 있지만, 인수의 부분을 x.Key로 변경하면 Key를 기준으로 정렬하는 것도 가능하다.

KeyValuePair의 List를 사용하는 방법

foreach로 Key, Value를 함께 얻어낼 때 사용하던 KeyValuePair 구조체를 데이터형으로 하여 리스트로 작성하는 것이 가능하다. 리스트로 만들어지면, 리스트로써 정렬하는 것이 가능하므로 편리하다. 예시를 살펴보자.

using System;
using System.Collections.Generic;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var myTable = new Dictionary<string, string>();
      myTable.Add("Hokkaido", "Sapporo");
      myTable.Add("Iwate", "Morioka");
      myTable.Add("Miyagi", "Sendai");
      
      var list = new List<KeyValuePair<string, string>>(myTable);
      list.Sort((a, b) => b.Key.CompareTo(a.Key));
      
      foreach(var item in list) {
        Console.WriteLine("[{0}:{1}]", item.Key, item.Value);
      }
      
      Console.ReadKey();
    }
  }
}

실행 결과:

[Miyagi:Sendai]
[Iwate:Morioka]
[Hokkaido:Sapporo]

 이 예시에서는 KeyValuePair 구조체를 요소의 데이터형으로하여 List의 객체 list로 만들고 있다. 그리고 다시 list에 대해 Sort메소드를 호출하여 인수에 람다식을 지정하여 Key를 기준으로 역정렬하고 있다. 

 이 경우에도 람다식의 일부를 b.Value.CompareTo(a.Value)로 변경하여 Value를 기준으로 정렬하는 것도 가능하다.

 List 데이터형의 객체의 경우, 이번에 소개한 람다식이외에 delegate를 사용하는 방법이나 Compare 메소드, CompareTo메소드를 사용하는 방법과 같은 다양한 방법이 있다. 

 

 

List와의 상호호환


앞에 정렬 이야기에서도 나왔지만, Dictionary형의 객체를 List형으로 변환하면 편리한 경우가 있다. 역으로 List형의 객체를 Dictionary형으로 변환하는 경우도 있다.

 각각의 변환방법을 살펴보자.

Dictionary에서 List로 변환하기

Dictionary의 Key나 Value를 List로 변환하는 방법을 살펴보자. Dictionary의 Keys 속성이나 Values 속성을 사용하여 Key의 값만 혹은 Value의 값만을 취득할 수 있었다.

 이것을 List형의 객체로 선언, 정의할 때 생성자의 인수로 지정하는 것으로 복사본을 만들 수 있다. 예시를 확인해보자.

using System;
using System.Collections.Generic;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var myTable = new Dictionary<string, string>();
      myTable.Add("Hokkaido", "Sapporo");
      myTable.Add("Iwate", "Morioka");
      myTable.Add("Miyagi", "Sendai");
      
      var kList = new List<string>(myTable.Keys);
      var vList = new List<string>(myTable.Values);
      
      Console.WriteLine("[{0}]", string.Join(", ", kList));
      Console.WriteLine("[{0}]", string.Join(", ", vList));
      
      Console.ReadKey();
    }
  }
}

실행결과:

[Hokkaido, Iwate, Miyagi]
[Sapporo, Morioka, Sendai]

List에서 Dictionary로 변환하기

 2개의 List를 Dictionary로 변환하는 방법에 대해 소개하도록 하겠다. LINQ의 Zip메소드를 사용하여 2개의 List 요소로 속성을 가진 익명형의 시퀀스를 만든다. 이것을 다시 ToDictionary메소드로 Dictionary형으로 변환한다.

 예시를 확인해보자.

using System;
using System.Collections.Generic;
using System.Linq;
 
namespace Sample
{
  class Sample
  {
    static void Main()
    {
      var kList = new List<string>();
      kList.Add("Hokkaido");
      kList.Add("Iwate");
      kList.Add("Miyagi");
      
      var vList = new List<string>();
      vList.Add("Sapporo");
      vList.Add("Morioka");
      vList.Add("Sendai");
      
      Dictionary<string, string> myTable = 
        kList.Zip(vList, (k, v) => new { k, v }).ToDictionary(a => a.k, a => a.v);
      
      foreach(KeyValuePair<string, string> item in myTable) {
        Console.WriteLine("[{0}:{1}]", item.Key, item.Value);  
      }
      
      Console.ReadKey();
    }
  }
}

실행결과:

[Hokkaido:Sapporo]
[Iwate:Morioka]
[Miyagi:Sendai]

참고자료

www.sejuku.net/blog/41326

itsakura.com/csharp-dictionary

728x90