2009-03-26 3 views
18

내 프로그램에서 해시 세트를 사용하고 싶습니다. 사전을 사용하면 추한 느낌이 들게됩니다. 아마. NET 3.5와 함께 VS2008을 사용하기 시작할 것입니다. 그래서 내 이상은 비록 내가 (또는 할 수 있겠습니까?) VS2005에서 hashsets을 사용할 수 있습니다. .NET 3.5를 사용하기 시작할 때, 나는 원하지 않습니다. 이 해시 세트를 사용하도록 전환하려면 많은 것을 변경해야합니다.3.5와 호환되는 C# 2.0에서 HashSet 사용

누구든지 이것을 염두에두고 설계된 기존의 해시 세트 구현을 알고 있거나 VS2005에서 3.5 해시 세트를 사용하는 방법을 알고 있는지 궁금합니다.

답변

23

2.0 응용 프로그램에서 HashSet<T>을 사용할 수 있습니다. 단지 System.Core.dll을 참조하기 만하면됩니다.

참고 : 이렇게하면 무료이며 Visual Studio와 별도로 .NET 3.5 framework을 설치해야합니다. 설치가 완료되면 HashSet<T> 유형을 포함하는 새로운 System.Core 어셈블리가 생성됩니다. .NET Framework 버전 2.0 - 3.5가 모두 동일한 CLR을 공유하므로 2.0 어셈블리에서이 어셈블리를 아무런 문제없이 사용할 수 있습니다.

+1

그러나 XP 이상이어야합니다. 그게 내가 만난 문제이고 왜 내 HashSet을 만들지 않았습니까 . 우리는 XP에서 개발하고 모든 훌륭한 VS 2008 항목을 얻습니다. 그러나 모든 클라이언트는 Win2K에 있고 .NET 3.5 프레임 워크를 실행할 수 없으므로 .NET 2.0을 대상으로해야합니다. –

+1

System.Core에서 HashSet을 추출해 내 어셈블리로 컴파일 할 수 없습니까? –

+5

네, 그럴 수는 있지만 그렇게해서는 안된다는 의미는 아닙니다. 이 프레임 워크의 라이센스는 바로이 것을 금지합니다. –

1

using 지시문을 사용하여 Dictionary를 Hashset으로 별칭 지정할 수 있습니다. 실제로는 똑같은 것은 아니지만 나중에 사물을 단순화 할 수 있습니다.

2

나는 PowerCollections 라이브러리가 귀하의 필요에 맞아야한다고 생각합니다. 이것은 .NET에서 누락 된 여러 컬렉션 클래스를 포함하는 오픈 소스 라이브러리입니다. Set<T>, Bag<T>, MultiDictionary 등이 있습니다. .NET 2.0에서 실행됩니다. 나는 2 년 전부터이 제품을 사용 해왔고 그 제품에 매우 만족하고 있습니다.

3

C5 Library 또한 HashSet의 구현을 가지고 사용할 수 있습니다.

24

여기에 Dictionary < T, 개체 >을 내부적으로 사용하는 2.0에 대해 쓴 글이 있습니다. 3.5 HashSet <T>의 정확한 일치는 아니지만 나를 위해 일합니다.

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.Runtime.Serialization; 

public class HashSet<T> : ICollection<T>, ISerializable, IDeserializationCallback 
{ 
    private readonly Dictionary<T, object> dict; 

    public HashSet() 
    { 
     dict = new Dictionary<T, object>(); 
    } 

    public HashSet(IEnumerable<T> items) : this() 
    { 
     if (items == null) 
     { 
      return; 
     } 

     foreach (T item in items) 
     { 
      Add(item); 
     } 
    } 

    public HashSet<T> NullSet { get { return new HashSet<T>(); } } 

    #region ICollection<T> Members 

    public void Add(T item) 
    { 
     if (null == item) 
     { 
      throw new ArgumentNullException("item"); 
     } 

     dict[item] = null; 
    } 

    /// <summary> 
    /// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
    /// </summary> 
    /// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. </exception> 
    public void Clear() 
    { 
     dict.Clear(); 
    } 

    public bool Contains(T item) 
    { 
     return dict.ContainsKey(item); 
    } 

    /// <summary> 
    /// Copies the items of the <see cref="T:System.Collections.Generic.ICollection`1"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index. 
    /// </summary> 
    /// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the items copied from <see cref="T:System.Collections.Generic.ICollection`1"/>. The <see cref="T:System.Array"/> must have zero-based indexing.</param><param name="arrayIndex">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null.</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="arrayIndex"/> is less than 0.</exception><exception cref="T:System.ArgumentException"><paramref name="array"/> is multidimensional.-or-<paramref name="arrayIndex"/> is equal to or greater than the length of <paramref name="array"/>.-or-The number of items in the source <see cref="T:System.Collections.Generic.ICollection`1"/> is greater than the available space from <paramref name="arrayIndex"/> to the end of the destination <paramref name="array"/>.-or-Type T cannot be cast automatically to the type of the destination <paramref name="array"/>.</exception> 
    public void CopyTo(T[] array, int arrayIndex) 
    { 
     if (array == null) throw new ArgumentNullException("array"); 
     if (arrayIndex < 0 || arrayIndex >= array.Length || arrayIndex >= Count) 
     { 
      throw new ArgumentOutOfRangeException("arrayIndex"); 
     } 

     dict.Keys.CopyTo(array, arrayIndex); 
    } 

    /// <summary> 
    /// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
    /// </summary> 
    /// <returns> 
    /// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>. 
    /// </returns> 
    /// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception> 
    public bool Remove(T item) 
    { 
     return dict.Remove(item); 
    } 

    /// <summary> 
    /// Gets the number of items contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
    /// </summary> 
    /// <returns> 
    /// The number of items contained in the <see cref="T:System.Collections.Generic.ICollection`1"/>. 
    /// </returns> 
    public int Count 
    { 
     get { return dict.Count; } 
    } 

    /// <summary> 
    /// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. 
    /// </summary> 
    /// <returns> 
    /// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false. 
    /// </returns> 
    public bool IsReadOnly 
    { 
     get 
     { 
      return false; 
     } 
    } 

    #endregion 

    public HashSet<T> Union(HashSet<T> set) 
    { 
     HashSet<T> unionSet = new HashSet<T>(this); 

     if (null == set) 
     { 
      return unionSet; 
     } 

     foreach (T item in set) 
     { 
      if (unionSet.Contains(item)) 
      { 
       continue; 
      } 

      unionSet.Add(item); 
     } 

     return unionSet; 
    } 

    public HashSet<T> Subtract(HashSet<T> set) 
    { 
     HashSet<T> subtractSet = new HashSet<T>(this); 

     if (null == set) 
     { 
      return subtractSet; 
     } 

     foreach (T item in set) 
     { 
      if (!subtractSet.Contains(item)) 
      { 
       continue; 
      } 

      subtractSet.dict.Remove(item); 
     } 

     return subtractSet; 
    } 

    public bool IsSubsetOf(HashSet<T> set) 
    { 
     HashSet<T> setToCompare = set ?? NullSet; 

     foreach (T item in this) 
     { 
      if (!setToCompare.Contains(item)) 
      { 
       return false; 
      } 
     } 

     return true; 
    } 

    public HashSet<T> Intersection(HashSet<T> set) 
    { 
     HashSet<T> intersectionSet = NullSet; 

     if (null == set) 
     { 
      return intersectionSet; 
     } 

     foreach (T item in this) 
     { 
      if (!set.Contains(item)) 
      { 
       continue; 
      } 

      intersectionSet.Add(item); 
     } 

     foreach (T item in set) 
     { 
      if (!Contains(item) || intersectionSet.Contains(item)) 
      { 
       continue; 
      } 

      intersectionSet.Add(item); 
     } 

     return intersectionSet; 
    } 

    public bool IsProperSubsetOf(HashSet<T> set) 
    { 
     HashSet<T> setToCompare = set ?? NullSet; 

     // A is a proper subset of a if the b is a subset of a and a != b 
     return (IsSubsetOf(setToCompare) && !setToCompare.IsSubsetOf(this)); 
    } 

    public bool IsSupersetOf(HashSet<T> set) 
    { 
     HashSet<T> setToCompare = set ?? NullSet; 

     foreach (T item in setToCompare) 
     { 
      if (!Contains(item)) 
      { 
       return false; 
      } 
     } 

     return true; 
    } 

    public bool IsProperSupersetOf(HashSet<T> set) 
    { 
     HashSet<T> setToCompare = set ?? NullSet; 

     // B is a proper superset of a if b is a superset of a and a != b 
     return (IsSupersetOf(setToCompare) && !setToCompare.IsSupersetOf(this)); 
    } 

    public List<T> ToList() 
    { 
     return new List<T>(this); 
    } 

    #region Implementation of ISerializable 

    /// <summary> 
    /// Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo"/> with the data needed to serialize the target object. 
    /// </summary> 
    /// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to populate with data. </param><param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext"/>) for this serialization. </param><exception cref="T:System.Security.SecurityException">The caller does not have the required permission. </exception> 
    public void GetObjectData(SerializationInfo info, StreamingContext context) 
    { 
     if (info == null) throw new ArgumentNullException("info"); 
     dict.GetObjectData(info, context); 
    } 

    #endregion 

    #region Implementation of IDeserializationCallback 

    /// <summary> 
    /// Runs when the entire object graph has been deserialized. 
    /// </summary> 
    /// <param name="sender">The object that initiated the callback. The functionality for this parameter is not currently implemented. </param> 
    public void OnDeserialization(object sender) 
    { 
     dict.OnDeserialization(sender); 
    } 

    #endregion 

    #region Implementation of IEnumerable 

    /// <summary> 
    /// Returns an enumerator that iterates through the collection. 
    /// </summary> 
    /// <returns> 
    /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection. 
    /// </returns> 
    /// <filterpriority>1</filterpriority> 
    public IEnumerator<T> GetEnumerator() 
    { 
     return dict.Keys.GetEnumerator(); 
    } 

    /// <summary> 
    /// Returns an enumerator that iterates through a collection. 
    /// </summary> 
    /// <returns> 
    /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection. 
    /// </returns> 
    /// <filterpriority>2</filterpriority> 
    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 

    #endregion 
} 
+1

필요하다면 나를 공격하고, 실제로는 HashSet의 요점을 무시했습니다. HashSet.Contains() 메서드의 기능을 Dictionary.ConatinsKey() 메서드로 대체했습니다. 이 메소드는 O (n)이고 HashSet.Contains() 메소드는 O (1)입니다. 이 구현은 List 객체의 모든 속도를가집니다. – SamuelWarren

+0

@highphilosopher : 이것은 단지 HashSet 의 빠르고 근사한 근사치입니다.HashSet 및 기타 3.5 항목을 사용하면서 Win2K에서 사용자를 지원해야하므로 실제로 무엇을하고 무엇을하고 있는지, Mono의 System.Core를 2.0 용으로 다시 컴파일하고 VS 2008에서 개발해야합니다. 위의 코드는 제가 사용하고있는 몇 주 동안 제 목적을 달성했으며 작은 데이터 세트 이외에는 사용할 수 없습니다. –

+14

@highphilosopher : 그건 잘못되었습니다. 레코드의 경우,'Dictionary <>'키 메소드 ('ConstainsKey'를 포함)는 O (1) 구현을 해시하고 유사한 목적의 HashSet 메소드와 매우 유사합니다. 'ContainsValue'는 O (n)입니다. Dictionary의 목적 중 하나는 인덱스를 배열로 사용하는 대신 키를 고속으로 검색하는 것입니다. –

관련 문제