2008-12-19 28 views
39

Tôi cần tương đương với C++ 's std::multimap<K, V, Comp, Alloc> bằng chữ C. Nó có tồn tại trong thư viện chuẩn không?multimap in .NET

+6

Sử dụng danh sách trong từ điển thông thường đủ tốt hầu hết thời gian – Casebash

Trả lời

49

Bởi vì nó gần như giáng sinh :)

////////////////////////////////////////////////////////////////////// 
// Algorithmia is (c) 2008 Solutions Design. All rights reserved. 
// http://www.sd.nl 
////////////////////////////////////////////////////////////////////// 
// COPYRIGHTS: 
// Copyright (c) 2008 Solutions Design. All rights reserved. 
// 
// The Algorithmia library sourcecode and its accompanying tools, tests and support code 
// are released under the following license: (BSD2) 
// ---------------------------------------------------------------------- 
// Redistribution and use in source and binary forms, with or without modification, 
// are permitted provided that the following conditions are met: 
// 
// 1) Redistributions of source code must retain the above copyright notice, this list of 
// conditions and the following disclaimer. 
// 2) Redistributions in binary form must reproduce the above copyright notice, this list of 
// conditions and the following disclaimer in the documentation and/or other materials 
// provided with the distribution. 
// 
// THIS SOFTWARE IS PROVIDED BY SOLUTIONS DESIGN ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOLUTIONS DESIGN OR CONTRIBUTORS BE LIABLE FOR 
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
// 
// The views and conclusions contained in the software and documentation are those of the authors 
// and should not be interpreted as representing official policies, either expressed or implied, 
// of Solutions Design. 
// 
////////////////////////////////////////////////////////////////////// 
// Contributers to the code: 
//  - Frans Bouma [FB] 
////////////////////////////////////////////////////////////////////// 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using SD.Tools.Algorithmia.UtilityClasses; 

namespace SD.Tools.Algorithmia.GeneralDataStructures 
{ 
    /// <summary> 
    /// Extension to the normal Dictionary. This class can store more than one value for every key. It keeps a HashSet for every Key value. 
    /// Calling Add with the same Key and multiple values will store each value under the same Key in the Dictionary. Obtaining the values 
    /// for a Key will return the HashSet with the Values of the Key. 
    /// </summary> 
    /// <typeparam name="TKey">The type of the key.</typeparam> 
    /// <typeparam name="TValue">The type of the value.</typeparam> 
    public class MultiValueDictionary<TKey, TValue> : Dictionary<TKey, HashSet<TValue>> 
    { 
     /// <summary> 
     /// Initializes a new instance of the <see cref="MultiValueDictionary&lt;TKey, TValue&gt;"/> class. 
     /// </summary> 
     public MultiValueDictionary() 
      : base() 
     { 
     } 


     /// <summary> 
     /// Adds the specified value under the specified key 
     /// </summary> 
     /// <param name="key">The key.</param> 
     /// <param name="value">The value.</param> 
     public void Add(TKey key, TValue value) 
     { 
      ArgumentVerifier.CantBeNull(key, "key"); 

      HashSet<TValue> container = null; 
      if(!this.TryGetValue(key, out container)) 
      { 
       container = new HashSet<TValue>(); 
       base.Add(key, container); 
      } 
      container.Add(value); 
     } 


     /// <summary> 
     /// Determines whether this dictionary contains the specified value for the specified key 
     /// </summary> 
     /// <param name="key">The key.</param> 
     /// <param name="value">The value.</param> 
     /// <returns>true if the value is stored for the specified key in this dictionary, false otherwise</returns> 
     public bool ContainsValue(TKey key, TValue value) 
     { 
      ArgumentVerifier.CantBeNull(key, "key"); 
      bool toReturn = false; 
      HashSet<TValue> values = null; 
      if(this.TryGetValue(key, out values)) 
      { 
       toReturn = values.Contains(value); 
      } 
      return toReturn; 
     } 


     /// <summary> 
     /// Removes the specified value for the specified key. It will leave the key in the dictionary. 
     /// </summary> 
     /// <param name="key">The key.</param> 
     /// <param name="value">The value.</param> 
     public void Remove(TKey key, TValue value) 
     { 
      ArgumentVerifier.CantBeNull(key, "key"); 

      HashSet<TValue> container = null; 
      if(this.TryGetValue(key, out container)) 
      { 
       container.Remove(value); 
       if(container.Count <= 0) 
       { 
        this.Remove(key); 
       } 
      } 
     } 


     /// <summary> 
     /// Merges the specified multivaluedictionary into this instance. 
     /// </summary> 
     /// <param name="toMergeWith">To merge with.</param> 
     public void Merge(MultiValueDictionary<TKey, TValue> toMergeWith) 
     { 
      if(toMergeWith==null) 
      { 
       return; 
      } 

      foreach(KeyValuePair<TKey, HashSet<TValue>> pair in toMergeWith) 
      { 
       foreach(TValue value in pair.Value) 
       { 
        this.Add(pair.Key, value); 
       } 
      } 
     } 


     /// <summary> 
     /// Gets the values for the key specified. This method is useful if you want to avoid an exception for key value retrieval and you can't use TryGetValue 
     /// (e.g. in lambdas) 
     /// </summary> 
     /// <param name="key">The key.</param> 
     /// <param name="returnEmptySet">if set to true and the key isn't found, an empty hashset is returned, otherwise, if the key isn't found, null is returned</param> 
     /// <returns> 
     /// This method will return null (or an empty set if returnEmptySet is true) if the key wasn't found, or 
     /// the values if key was found. 
     /// </returns> 
     public HashSet<TValue> GetValues(TKey key, bool returnEmptySet) 
     { 
      HashSet<TValue> toReturn = null; 
      if(!base.TryGetValue(key, out toReturn) && returnEmptySet) 
      { 
       toReturn = new HashSet<TValue>(); 
      } 
      return toReturn; 
     } 
    } 
} 
+0

CHỈNH SỬA: Tôi bỏ lỡ - Ban đầu tôi nghĩ rằng điều này sẽ phá vỡ LSP (có thể *) - nhưng tôi nghĩ là không sao vì nó không ẩn bất kỳ phương thức lớp cơ sở nào và chúng vẫn hoạt động như mong đợi. Bỏ phiếu xuống hoàn trả :) – mhand

14

ILookup có thể đủ tốt cho bạn - nhưng tiếc là không có triển khai công cộng. Bạn đã cơ bản phải đi qua Enumerable.ToLookup, theo như tôi biết. Điều đó có nghĩa đó là loại bản đồ "xây dựng một lần" - bạn không thể thêm vào bản đồ sau này. Tuy nhiên, nếu đó là tất cả những gì bạn cần, thật thuận tiện để có thể sử dụng công cụ tích hợp sẵn.

7

Trong .NET 3.5, có một ILookup<,> đại diện cho điều này. Việc triển khai thường xuyên (Lookup<,>) là không thay đổi, nhưng tôi có một số EditableLookup<,> trong số MiscUtil nên thực hiện công việc một cách độc đáo.

2

bạn có thể thử này

C# Multimap Generic Class

http://dotnetperls.com/multimap

thực hiện Multimap Rất đơn giản.

+0

Tiện dụng, nhưng tôi không thấy thông tin giấy phép có nghĩa là nó không thực sự có thể sử dụng như sau: / –

0

Cân nhắc sử dụng BMultiMap<K,V> nếu toàn bộ bộ sưu tập của bạn lớn. Nó tiết kiệm rất nhiều bộ nhớ so với Dictionary<K,List<V>>, đặc biệt nếu số lượng giá trị liên quan đến mỗi khóa thường nhỏ.