2009-03-26 4 views
18

私のプログラムでは実際にハッシュセットを使いたいと思っています。辞書を使うと醜いと感じる。私はおそらく.Net 3.5を使ってVS2008を使用し始めるでしょう。私の理想は、VS2005でhashsetsを使用することはできませんが(またはできますか?これらのハッシュセットの使用に切り替えるために、何かを変更する必要があります。C#2.0でのHashSetの使用、3.5との互換性

これを念頭に置いて設計された既存のハッシュセット実装、または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をハッシュセットとしてエイリアスすることができます。実際には同じことではありませんが、後であなたのために物事を簡素化するかもしれません。

2

私はPowerCollectionsライブラリがあなたのニーズに合っているはずだと思います。それはSet<T>Bag<T>MultiDictionaryなどを含む.NETで見つからなかったいくつかのコレクションクラスを含むオープンソースライブラリです。それは.NET 2.0で動作します。私は数年前から使ってきましたが、とても満足しています。

8

あなたは(NHibernateので使用)Iesi.CollectionsまたはMono's HashSet

+0

+! MonoのHashSetのリンクについては、私がGoogleからここに来て欲しいと思っていたものでした。 – PiotrK

3

C5 LibraryもHashSetの実装を持っているを使用することができます。

24

ここでは、辞書< 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)です。この実装はリストオブジェクトのすべての速度を持っています。 – 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の目的の1つは、インデックスを配列として使用するのではなく、キーを高速に検索することです。 –

関連する問題