// Copyright (c) 2014, Yves Goergen, http://unclassified.software/source/collectiondictionary
//
// Copying and distribution of this file, with or without modification, are permitted provided the
// copyright notice and this notice are preserved. This file is offered as-is, without any warranty.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Unclassified.Util
{
///
/// Implements a dictionary that can store multiple values for each key.
///
/// The type of the keys in the dictionary.
/// The type of the values in the dictionary.
public class CollectionDictionary : Dictionary>
{
#region Private data
///
/// The empty collection to return in .
///
private TValue[] empty = new TValue[0];
#endregion Private data
#region Constructors
///
/// Initializes a new instance of the class
/// that is empty, has the default initial capacity, and uses the default equality comparer
/// for the key type.
///
public CollectionDictionary()
{
}
///
/// Initializes a new instance of the class
/// that contains elements copied from the specified
/// and uses the default equality comparer for the key type.
///
/// The dictionary whose elements are copied to the new
/// .
public CollectionDictionary(IDictionary dictionary)
{
LoadFromDictionary(dictionary);
}
///
/// Initializes a new instance of the class
/// that is empty, has the default initial capacity, and uses the specified
/// .
///
/// The implementation to use when
/// comparing keys, or null to use the default for the
/// type of the key.
public CollectionDictionary(IEqualityComparer comparer)
: base(comparer)
{
}
///
/// Initializes a new instance of the class
/// that is empty, has the specified initial capacity, and uses the default equality
/// comparer for the key type.
///
/// The initial number of elements that the
/// can contain.
public CollectionDictionary(int capacity)
: base(capacity)
{
}
///
/// Initializes a new instance of the class
/// that contains elements copied from the specified
/// and uses the specified .
///
/// The dictionary whose elements are copied to the new
/// .
/// The implementation to use when
/// comparing keys, or null to use the default for the
/// type of the key.
public CollectionDictionary(IDictionary dictionary, IEqualityComparer comparer)
: base(comparer)
{
LoadFromDictionary(dictionary);
}
///
/// Initializes a new instance of the class
/// that is empty, has the specified initial capacity, and uses the specified
/// .
///
/// The initial number of elements that the
/// can contain.
/// The implementation to use when
/// comparing keys, or null to use the default for the
/// type of the key.
public CollectionDictionary(int capacity, IEqualityComparer comparer)
: base(capacity, comparer)
{
}
///
/// Initializes the contents from a
/// instance.
///
/// The dictionary to copy elements from.
private void LoadFromDictionary(IDictionary dictionary)
{
foreach (var kvp in dictionary)
{
var list = new List();
list.Add(kvp.Value);
Add(kvp.Key, list);
}
}
#endregion Constructors
#region Data access
///
/// Gets the count of all values for all keys.
///
public int ValueCount
{
get
{
int count = 0;
foreach (var kvp in this)
{
count += kvp.Value.Count;
}
return count;
}
}
///
/// Adds the specified value to a key in the dictionary.
///
/// The key of the element to add the value to.
/// The value to add to the key. The value can be null for reference types.
public void Add(TKey key, TValue value)
{
ICollection collection;
if (!TryGetValue(key, out collection))
{
collection = new List();
base.Add(key, collection);
}
collection.Add(value);
}
///
/// Adds multiple values to a key in the dictionary.
///
/// The key of the element to add the values to.
/// The values to add to the key.
public void AddRange(TKey key, IEnumerable values)
{
ICollection collection;
if (!TryGetValue(key, out collection))
{
collection = new List();
base.Add(key, collection);
}
foreach (TValue value in values)
{
collection.Add(value);
}
}
///
/// Removes the value from the specified key in the dictionary.
///
/// The key of the element to remove the value from.
/// The value to remove from the key. The value can be null for reference types.
public void RemoveValue(TKey key, TValue value)
{
ICollection collection;
if (TryGetValue(key, out collection))
{
collection.Remove(value);
if (collection.Count == 0)
{
Remove(key);
}
}
}
///
/// Determines whether the dictionary contains a specific value in any key.
///
/// The value to locate in the dictionary. The value can be null for reference types.
/// true if the dictionary contains the specified value; otherwise, false.
public bool ContainsValue(TValue value)
{
foreach (var kvp in this)
{
if (kvp.Value.Contains(value)) return true;
}
return false;
}
///
/// Returns a collection of values for the specified key. If the key does not exist in the
/// dictionary, an empty collection is returned.
///
/// The key of the element to return the values from.
///
public ICollection GetValuesOrEmpty(TKey key)
{
ICollection values;
if (TryGetValue(key, out values))
{
return values;
}
return empty;
}
#endregion Data access
}
}