본문 바로가기

프로그래밍&IT/C#

C# Hashtable 클래스 (.net framework 3.5 기준 / MSDN)

Hashtable 클래스

 

* 네임스페이스 : System.Collections

[SerializableAttribute]
[ComVisibleAttribute(true)]
public class Hashtable : IDictionary, ICollection,
IEnumerable, ISerializable, IDeserializationCallback, ICloneable

* 설명

각 요소는 DictionaryEntry 개체에 저장된 키/값 쌍입니다. 키는 null일 수 없으나 값은 null일 수 있습니다

 

Hashtable에서 키로 사용하는 개체는 Object.GetHashCode 메서드(또는 IHashCodeProvider 인터페이스) 및 Object.Equals 메서드(또는 IComparer 인터페이스)를 재정의하는 데 필요합니다. 두 메서드 및 인터페이스 구현에서는 동일한 방식으로 대/소문자를 구분해야 합니다. 그렇지 않으면, Hashtable이 올바로 동작하지 않을 수 있습니다. 예를 들어, Hashtable을 만들 때 CaseInsensitiveComparer 클래스나 대/소문자를 구분하지 않는 IComparer 구현과 함께 CaseInsensitiveHashCodeProvider 클래스나 대/소문자를 구분하지 않는 IHashCodeProvider 구현을 사용해야 합니다.

또한 키가 Hashtable에 있는 동안에는 동일한 매개 변수를 사용하여 메서드를 호출할 때 동일한 결과가 생성되어야 합니다. 또는 IEqualityComparer 매개 변수와 함께 Hashtable 생성자를 사용할 수도 있습니다. 키 일치가 단순히 참조 일치이면 Object.GetHashCodeObject.Equals를 상속하여 구현하면 됩니다.

Hashtable에서 키 개체를 키로 사용하는 동안에는 해당 개체를 변경하지 않아야 합니다.

요소는 Hashtable에 추가될 때 키의 해시 코드에 따라 버킷에 배치됩니다. 키를 계속해서 조회하는 경우 해당 키의 해시 코드를 사용하여 특정 버킷 하나에서만 검색하므로 실제로 특정 요소를 찾는 데 필요한 키 비교 횟수가 줄어듭니다.

Hashtable의 로드 비율에 따라 버킷과 요소의 최대 비율이 결정됩니다. 로드 비율이 작을수록 메모리는 더 많이 소모되지만 평균 조회 시간은 빨라집니다. 일반적으로 기본 로드 비율 1.0은 적절한 속도와 크기를 제공합니다. Hashtable을 만들 때 다른 로드 비율을 지정할 수도 있습니다.

요소가 Hashtable에 추가되면 Hashtable의 실제 로드 비율이 증가합니다. 실제 로드 비율이 지정된 로드 비율에 도달하면 Hashtable의 버킷 수는 자동으로 현재 Hashtable 버킷 수의 두 배가 넘는 최소의 소수로 증가합니다.

Hashtable의 각 키 개체는 GetHash를 호출하여 액세스할 수 있는 자체 해시 함수를 제공해야 합니다. 그러나 IHashCodeProvider를 구현하는 개체는 Hashtable 생성자에 전달될 수 있으며 테이블의 모든 개체에 대해 해당 해시 함수가 사용됩니다.

Hashtable의 용량은 Hashtable에 보유할 수 있는 요소의 수입니다. 요소가 Hashtable에 추가될 때 필요하면 재할당을 통해 용량이 자동으로 증가됩니다.

 

* 예제

using System;
using System.Collections;

class Example
{
    public static void Main()
    {
        // Create a new hash table.
        //
        Hashtable openWith = new Hashtable();

        // Add some elements to the hash table. There are no
        // duplicate keys, but some of the values are duplicates.
        openWith.Add("txt", "notepad.exe");
        openWith.Add("bmp", "paint.exe");
        openWith.Add("dib", "paint.exe");
        openWith.Add("rtf", "wordpad.exe");

        // The Add method throws an exception if the new key is
        // already in the hash table.
        try
        {
            openWith.Add("txt", "winword.exe");
        }
        catch
        {
            Console.WriteLine("An element with Key = \"txt\" already exists.");
        }

        // The Item property is the default property, so you
        // can omit its name when accessing elements.
        Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);

        // The default Item property can be used to change the value
        // associated with a key.
        openWith["rtf"] = "winword.exe";
        Console.WriteLine("For key = \"rtf\", value = {0}.", openWith["rtf"]);

        // If a key does not exist, setting the default Item property
        // for that key adds a new key/value pair.
        openWith["doc"] = "winword.exe";

        // ContainsKey can be used to test keys before inserting
        // them.
        if (!openWith.ContainsKey("ht"))
        {
            openWith.Add("ht", "hypertrm.exe");
            Console.WriteLine("Value added for key = \"ht\": {0}", openWith["ht"]);
        }

        // When you use foreach to enumerate hash table elements,
        // the elements are retrieved as KeyValuePair objects.
        Console.WriteLine();
        foreach( DictionaryEntry de in openWith )
        {
            Console.WriteLine("Key = {0}, Value = {1}", de.Key, de.Value);
        }

        // To get the values alone, use the Values property.
        ICollection valueColl = openWith.Values;

        // The elements of the ValueCollection are strongly typed
        // with the type that was specified for hash table values.
        Console.WriteLine();
        foreach( string s in valueColl )
        {
            Console.WriteLine("Value = {0}", s);
        }

        // To get the keys alone, use the Keys property.
        ICollection keyColl = openWith.Keys;

        // The elements of the KeyCollection are strongly typed
        // with the type that was specified for hash table keys.
        Console.WriteLine();
        foreach( string s in keyColl )
        {
            Console.WriteLine("Key = {0}", s);
        }

        // Use the Remove method to remove a key/value pair.
        Console.WriteLine("\nRemove(\"doc\")");
        openWith.Remove("doc");

        if (!openWith.ContainsKey("doc"))
        {
            Console.WriteLine("Key \"doc\" is not found.");
        }
    }
}

-> Hashtable로부터 key값 직접 핸들링할 때 예시.

//시나리오

//동일한 키값이 들어오면

//해당 키의 Count (변수= nCount)를 하나 증가시켜

//동일한 키가 들어온 카운팅하기.

 

string str = "HT"; //Hashtable Key지정

ht.Add(str, 1);   //key, value 저장

 

int nCount = 0;  //int 임시 변수

nCount = (int)ht[str]; // 배열처럼 [ ] 을 사용하여, 해당 key의 value를 얻어 오고

nCount++;   //Count을 한 후

ht[str] = nCount;  // 불러왔던 key에 value를 직접 집어 넣어준다.