Introduction
This article presents a generic sparse array class in C#, and generic sparse matrix classes that take from 2 to 8 key values. The sparse array class is named SparseArray
and the sparse matrix classes are named Sparse2D
Matrix
through Sparse8D
Matrix
respectively.
A simple program named SparseCollectionTest
is provided to demonstrate the use of these classes.
Because these are all generic types, almost any type can be used either for the keys or the item that is stored in the sparse container. The only special requirement is that the key types must implement the IComparable
interface.
These sparse containers are not as efficient as a fixed size array or a fixed size matrix, and so should only be used when necessary.
A sparse array or a sparse matrix is useful when most of an array or a matrix will not be written. This is often the case in mathematics, so if the item type and key types are numeric types, these containers can be very useful for solutions in linear algebra. The containers can also be used to implement simple associative memories.
Background
I originally wrote a C# SparseArray
class in April 2010. I also wanted a sparse matrix class for a linear equation solver. I created Sparse2DMatrix
through Sparse8DMatrix
long before Microsoft had added Tuple
classes to .NET.
Because Tuples were not available back then, I created classes Group2
through Group8
. Based on feedback from a CodeProject user, I have renamed these ComparableTuple2
through ComparableTuple8
. These classes are used internally in the Sparse2D
Matrix
through Sparse8D
Matrix
respectively. ComparableTuple
2
through ComparableTuple
8
class instances are immutable by design, because the hash code for a comparable tuple instance depends on key values, and the hash code for a type instance should not be changed.
I cannot currently develop with .NET 4.x, but it probably would be easy to modify these classes to use the Tuple
classes, although since I don't have access to those classes, I'm not sure whether they implement the IComparable
interface, or if there isn't some other limitation. I did see from reading the documentation that those classes provide a Create
method that makes it unnecessary to declare the generic type using angle brackets when instantiating an instance. This is nice feature that my sparse collection types don't provide. In any event, these work just fine as is.
List of Files
- Program.cs - The main program
- SparseCollectionTest.csproj - The Visual Studio C# project file
- SparseCollectionTest.sln - The Visual Studio C# solution file
- AssemblyInfo.cs - Contains information about the program
- ComparableTuple2.cs - Stores 2 keys, and is used in the
Sparse2DMatrix
class
- ComparableTuple3.cs - Stores 2 keys, and is used in the
Sparse3DMatrix
class
- ComparableTuple4.cs - Stores 2 keys, and is used in the
Sparse4DMatrix
class
- ComparableTuple5.cs - Stores 2 keys, and is used in the
Sparse5DMatrix
class
- ComparableTuple6.cs - Stores 2 keys, and is used in the
Sparse6DMatrix
class
- ComparableTuple7.cs - Stores 2 keys, and is used in the
Sparse7DMatrix
class
- ComparableTuple8.cs - Stores 2 keys, and is used in the
Sparse8DMatrix
class
- SparseArray.cs - An associative array that takes 1 key to access an item
- Sparse2DMatrix.cs - An associative array that takes 2 keys to access an item
- Sparse3DMatrix.cs - An associative array that takes 3 keys to access an item
- Sparse4DMatrix.cs - An associative array that takes 4 keys to access an item
- Sparse5DMatrix.cs - An associative array that takes 5 keys to access an item
- Sparse6DMatrix.cs - An associative array that takes 6 keys to access an item
- Sparse7DMatrix.cs - An associative array that takes 7 keys to access an item
- Sparse8DMatrix.cs - An associative array that takes 8 keys to access an item
Using a Sparse Array
Creating and using a SparseArray
instance is very easy. Below shows a SparseArray
instance with a key-type of int
and a item-type of double
. Then a value of 100.0
is stored at key value 10
, and a value of 12345.0
is stored at key value 20
.
SparseArray<int, double> vector = new SparseArray<int, double>(0.0);
vector[10] = 100.0;
vector[20] = 12345.0;
Any value in the SparseArray
can be obtained. The following line of code gets the value at key item 15
.
double value = vector[15];;
The following code prints all the key-value pairs in the sparse array.
foreach(KeyValuePair<int, double> pair in vector)
{
Console.WriteLine("pair vector[{0}] = {1}", pair.Key, pair.Value);
Using A Sparse Matrix
Below shows a Sparse3DMatrix
instance with three key-types of int
and a item-type of double
. A value of 1111.0
is stored at the key set (11, 22, 33
). This example shows keys that are the same type, but this is not necessary. They key types can be different. One key could be a string
, one an int
, and the other a float
.
Sparse3DMatrix<int, int, int, double> matrix = new Sparse3DMatrix<int, int, double>();
matrix[11, 22, 33] = 1111.0;
To iterate over sparse matrix keys and the value, use the following code. The code takes advantage of the matrix instances SeparateCombinedKeys
method. All of the sparse matrix classes provide this method. The correct comparable tuple class, which is ComparableTuple3
for a Sparse3DMatrix
, must have the correct key types, the same types used to instantiate the Sparse3DMatrix
instance.
foreach (KeyValuePair<ComparableTuple3<int, int, int>, double> pair3D in matrix3D)
{
int key0 = 0;
int key1 = 0;
int key2 = 0;
matrix3D.SeparateCombinedKeys(pair3D.Key, ref key0, ref key1, ref key2);
Console.WriteLine("pair matrix[{0}, {1}, {2}] = {3}", key0, key1, key2, pair3D.Value);
}
The Main Program - File Program.cs
The main program creates each type of sparse container, stores data in the container, and then dumps the data in the container.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using SparseCollections;
namespace SparseCollectionTest
{
class Program
{
static void Main(string[] args)
{
SparseArray<int, double> vector = new SparseArray<int, double>(0.0);
vector[0] = 100.0;
Console.WriteLine("vector[{0}] = {1}", 0, vector[0]);
Console.WriteLine("vector[{0}] = {1}", 1, vector[1]);
vector[0] = 90.0;
Console.WriteLine("vector[{0}] = {1}", 0, vector[0]);
foreach(KeyValuePair<int, double> pair in vector)
{
Console.WriteLine("pair vector[{0}] = {1}", pair.Key, pair.Value);
}
Sparse2DMatrix<int, int, double> matrix = new Sparse2DMatrix<int, int, double>();
matrix[0, 0] = 200.0;
matrix[0, 1] = 201.0;
matrix[1, 0] = 210.0;
Console.WriteLine("matrix[{0}, {1}] = {2}", 0, 0, matrix[0, 0]);
Console.WriteLine("matrix[{0}, {1}] = {2}", 0, 1, matrix[0, 1]);
Console.WriteLine("matrix[{0}, {1}] = {2}", 1, 0, matrix[1, 0]);
Console.WriteLine("matrix[{0}, {1}] = {2}", 1, 1, matrix[1, 1]);
foreach (KeyValuePair<ComparableTuple2<int, int>, double> pair in matrix)
{
int key0 = 0;
int key1 = 0;
matrix.SeparateCombinedKeys(pair.Key, ref key0, ref key1);
Console.WriteLine("pair matrix[{0}, {1}] = {2}", key0, key1, pair.Value);
}
Sparse3DMatrix<int, int, int, double> matrix3D =
new Sparse3DMatrix<int, int, int, double>();
matrix3D[0, 0, 0] = 3000.0;
matrix3D[0, 1, 0] = 3010.0;
matrix3D[1, 0, 1] = 3101.0;
Console.WriteLine("matrix3D[{0}, {1}, {2}] = {3}", 0, 0, 0, matrix3D[0, 0, 0]);
Console.WriteLine("matrix3D[{0}, {1}, {2}] = {3}", 0, 1, 0, matrix3D[0, 1, 0]);
Console.WriteLine("matrix3D[{0}, {1}, {2}] = {3}", 1, 0, 1, matrix3D[1, 0, 1]);
Console.WriteLine("matrix3D[{0}, {1}, {2}] = {3}", 1, 1, 1, matrix3D[1, 1, 1]);
foreach (KeyValuePair<ComparableTuple3<int, int, int>, double> pair3D in matrix3D)
{
int key0 = 0;
int key1 = 0;
int key2 = 0;
matrix3D.SeparateCombinedKeys(pair3D.Key, ref key0, ref key1, ref key2);
Console.WriteLine("pair matrix[{0}, {1}, {2}] = {3}", key0, key1, key2, pair3D.Value);
}
Sparse4DMatrix<int, int, int, int, double> matrix4D =
new Sparse4DMatrix<int, int, int, int, double>();
matrix4D[0, 0, 0, 0] = 40000.0;
matrix4D[0, 1, 0, 1] = 40101.0;
matrix4D[1, 0, 1, 0] = 41010.0;
Console.WriteLine(String.Format("matrix4D[{0},
{1}, {2}, {3}] = {4}", 0, 0, 0, 0, matrix4D[0, 0, 0, 0]));
Console.WriteLine(String.Format("matrix4D[{0},
{1}, {2}, {3}] = {4}", 0, 1, 0, 1, matrix4D[0, 1, 0, 1]));
Console.WriteLine(String.Format("matrix4D[{0},
{1}, {2}, {3}] = {4}", 1, 0, 1, 0, matrix4D[1, 0, 1, 0]));
Console.WriteLine(String.Format("matrix4D[{0},
{1}, {2}, {3}] = {4}", 1, 1, 1, 1, matrix4D[1, 1, 1, 1]));
foreach (KeyValuePair<ComparableTuple4<int, int, int, int>, double> pair4D in matrix4D)
{
int key0 = 0;
int key1 = 0;
int key2 = 0;
int key3 = 0;
matrix4D.SeparateCombinedKeys(pair4D.Key, ref key0, ref key1, ref key2, ref key3);
Console.WriteLine("pair matrix[{0},
{1}, {2}, {3}] = {4}", key0, key1, key2, key3, pair4D.Value);
}
Sparse5DMatrix<int, int, int, int, int, double> matrix5D =
new Sparse5DMatrix<int, int, int, int, int, double>();
matrix5D[0, 0, 0, 0, 0] = 500000.0;
matrix5D[0, 1, 0, 1, 0] = 501010.0;
matrix5D[1, 0, 1, 0, 1] = 510101.0;
Console.WriteLine(String.Format("{0}", matrix5D[0, 0, 0, 0, 0]));
Console.WriteLine(String.Format("{0}", matrix5D[0, 1, 0, 1, 0]));
Console.WriteLine(String.Format("{0}", matrix5D[1, 0, 1, 0, 1]));
Console.WriteLine(String.Format("{0}", matrix5D[1, 1, 1, 1, 1]));
foreach (KeyValuePair<ComparableTuple5<int,
int, int, int, int>, double> pair5D in matrix5D)
{
int key0 = 0;
int key1 = 0;
int key2 = 0;
int key3 = 0;
int key4 = 0;
matrix5D.SeparateCombinedKeys(pair5D.Key,
ref key0,
ref key1,
ref key2,
ref key3,
ref key4);
Console.WriteLine("pair matrix[{0}, {1}, {2}, {3}, {4}] = {5}",
key0, key1, key2, key3, key4, pair5D.Value);
}
Sparse6DMatrix<int, int, int, int, int, int, double> matrix6D =
new Sparse6DMatrix<int, int, int, int, int, int, double>();
matrix6D[0, 0, 0, 0, 0, 0] = 6000000.0;
matrix6D[0, 1, 0, 1, 0, 1] = 6010101.0;
matrix6D[1, 0, 1, 0, 1, 0] = 6101010.0;
Console.WriteLine(String.Format("{0}", matrix6D[0, 0, 0, 0, 0, 0]));
Console.WriteLine(String.Format("{0}", matrix6D[0, 1, 0, 1, 0, 1]));
Console.WriteLine(String.Format("{0}", matrix6D[1, 0, 1, 0, 1, 0]));
Console.WriteLine(String.Format("{0}", matrix6D[1, 1, 1, 1, 1, 1]));
foreach (KeyValuePair<ComparableTuple6<int, int,
int, int, int, int>, double> pair6D in matrix6D)
{
int key0 = 0;
int key1 = 0;
int key2 = 0;
int key3 = 0;
int key4 = 0;
int key5 = 0;
matrix6D.SeparateCombinedKeys(pair6D.Key,
ref key0,
ref key1,
ref key2,
ref key3,
ref key4,
ref key5);
Console.WriteLine("pair matrix[{0}, {1}, {2}, {3}, {4}, {5}] = {6}",
key0, key1, key2, key3, key4, key5, pair6D.Value);
}
Sparse7DMatrix<int, int, int, int, int, int, int, double> matrix7D =
new Sparse7DMatrix<int, int, int, int, int, int, int, double>();
matrix7D[0, 0, 0, 0, 0, 0, 0] = 70000000.0;
matrix7D[0, 1, 0, 1, 0, 1, 0] = 70101010.0;
matrix7D[1, 0, 1, 0, 1, 0, 1] = 71010101.0;
Console.WriteLine(String.Format("{0}", matrix7D[0, 0, 0, 0, 0, 0, 0]));
Console.WriteLine(String.Format("{0}", matrix7D[0, 1, 0, 1, 0, 1, 0]));
Console.WriteLine(String.Format("{0}", matrix7D[1, 0, 1, 0, 1, 0, 1]));
Console.WriteLine(String.Format("{0}", matrix7D[1, 1, 1, 1, 1, 1, 1]));
foreach (KeyValuePair<ComparableTuple7<int, int,
int, int, int, int, int>, double> pair7D in matrix7D)
{
int key0 = 0;
int key1 = 0;
int key2 = 0;
int key3 = 0;
int key4 = 0;
int key5 = 0;
int key6 = 0;
matrix7D.SeparateCombinedKeys(pair7D.Key,
ref key0,
ref key1,
ref key2,
ref key3,
ref key4,
ref key5,
ref key6);
Console.WriteLine("pair matrix[{0}, {1}, {2}, {3}, {4}, {5}, {6}] = {7}",
key0, key1, key2, key3, key4, key5, key6, pair7D.Value);
}
Sparse8DMatrix<int, int, int, int, int, int, int, int, double> matrix8D =
new Sparse8DMatrix<int, int, int, int, int, int, int, int, double>();
matrix8D[0, 0, 0, 0, 0, 0, 0, 0] = 800000000.0;
matrix8D[0, 1, 0, 1, 0, 1, 0, 1] = 801010101.0;
matrix8D[1, 0, 1, 0, 1, 0, 1, 0] = 810101010.0;
FileStream fileStream = null;
using (fileStream = new FileStream
("Matrix8.dat", FileMode.OpenOrCreate, FileAccess.Write))
{
BinaryFormatter binFormatter = new BinaryFormatter();
binFormatter.Serialize(fileStream, matrix8D);
}
Sparse8DMatrix<int, int, int, int, int, int, int, int, double> newMatrix8D =
new Sparse8DMatrix<int, int, int, int, int, int, int, int, double>();
using (fileStream = new FileStream("Matrix8.dat", FileMode.Open, FileAccess.Read))
{
BinaryFormatter binFormatter = new BinaryFormatter();
newMatrix8D =
(Sparse8DMatrix<int, int, int, int, int,
int, int, int, double>)binFormatter.Deserialize(fileStream);
}
Console.WriteLine(String.Format("{0}", newMatrix8D[0, 0, 0, 0, 0, 0, 0, 0]));
Console.WriteLine(String.Format("{0}", newMatrix8D[0, 1, 0, 1, 0, 1, 0, 1]));
Console.WriteLine(String.Format("{0}", newMatrix8D[1, 0, 1, 0, 1, 0, 1, 0]));
Console.WriteLine(String.Format("{0}", newMatrix8D[1, 1, 1, 1, 1, 1, 1, 1]));
foreach (KeyValuePair<ComparableTuple8<int, int, int,
int, int, int, int, int>, double> pair8D in newMatrix8D)
{
int key0 = 0;
int key1 = 0;
int key2 = 0;
int key3 = 0;
int key4 = 0;
int key5 = 0;
int key6 = 0;
int key7 = 0;
matrix8D.SeparateCombinedKeys(pair8D.Key,
ref key0,
ref key1,
ref key2,
ref key3,
ref key4,
ref key5,
ref key6,
ref key7);
Console.WriteLine("pair matrix[{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}] = {8}",
key0, key1, key2, key3, key4, key5, key6, key7, pair8D.Value);
}
Console.Write("Hit 'enter' to continue > ");
Console.ReadLine();
}
}
}
The SparseArray Class in File SparseArrays.cs
?
using System;
using System.Collections.Generic;
namespace SparseCollections
{
[Serializable]
public class SparseArray<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
where TKey : IComparable<TKey>
{
private Dictionary<TKey, TValue> m_dictionary;
public TValue DefaultValue
{
get;
set;
}
public int Count
{
get
{
return m_dictionary.Count;
}
}
#region Constructors
public SparseArray()
{
m_dictionary = new Dictionary<TKey, TValue>();
}
public SparseArray(TValue defaultValue)
{
m_dictionary = new Dictionary<TKey, TValue>();
DefaultValue = defaultValue;
}
public SparseArray(SparseArray<TKey, TValue> sparseArray)
{
m_dictionary = new Dictionary<TKey, TValue>();
Initialize(sparseArray);
DefaultValue = sparseArray.DefaultValue;
}
#endregion
private void Initialize(SparseArray<TKey, TValue> sparseArray)
{
m_dictionary.Clear();
foreach (KeyValuePair<TKey, TValue> pair in sparseArray)
{
m_dictionary.Add(pair.Key, pair.Value);
}
}
public void CopyTo(SparseArray<TKey, TValue> sparseArray)
{
sparseArray.m_dictionary.Clear();
foreach (KeyValuePair<TKey, TValue> pair in m_dictionary)
{
sparseArray.m_dictionary.Add(pair.Key, pair.Value);
}
}
public TValue this[TKey key]
{
get
{
TValue value;
if (!m_dictionary.TryGetValue(key, out value))
{
value = DefaultValue;
}
return value;
}
set
{
m_dictionary[key] = value;
}
}
public bool ContainsKey(TKey key)
{
return m_dictionary.ContainsKey(key);
}
public bool ContainsValue(TValue value)
{
return m_dictionary.ContainsValue(value);
}
public bool TryGetValue(TKey key, out TValue value)
{
return m_dictionary.TryGetValue(key, out value);
}
public bool Remove(TKey key)
{
return m_dictionary.Remove(key);
}
public void Clear()
{
m_dictionary.Clear();
}
#region IEnumerable<KeyValuePair<TKey, TValue>> Members
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return this.m_dictionary.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.m_dictionary.Values.GetEnumerator();
}
public TValue Current
{
get
{
return m_dictionary.Values.GetEnumerator().Current;
}
}
public bool MoveNext()
{
return m_dictionary.Values.GetEnumerator().MoveNext();
}
#endregion
}
A Sparse Matrix
I chose the Sparse3DMatrix
to describe all the sparse matrix classes. Shown first is the ComparableTuple3
class, which stores the key values for the Sparse3DMatrix
class.
The ComparableTuple3 Class in File ComparableTuple3.cs
?
using System;
using System.Collections.Generic;
namespace SparseCollections
{
[Serializable]
public class ComparableTuple3<TItem0, TItem1, TItem2>
: IComparable<ComparableTuple3<TItem0, TItem1, TItem2>>
where TItem0 : IComparable<TItem0>
where TItem1 : IComparable<TItem1>
where TItem2 : IComparable<TItem2>
{
public TItem0 Item0
{
get;
private set;
}
public TItem1 Item1
{
get;
private set;
}
public TItem2 Item2
{
get;
private set;
}
#region Constructors
public ComparableTuple3()
{
}
public ComparableTuple3(ComparableTuple3<TItem0, TItem1, TItem2> group)
{
Item0 = group.Item0;
Item1 = group.Item1;
Item2 = group.Item2;
}
public ComparableTuple3(TItem0 item0,
TItem1 item1,
TItem2 item2)
{
Item0 = item0;
Item1 = item1;
Item2 = item2;
}
#endregion
#region IComparable<ComparableTuple3> implementation
public int CompareTo(ComparableTuple3<TItem0, TItem1, TItem2> group)
{
int result = this.Item0.CompareTo(group.Item0);
if (result == 0)
{
result = this.Item1.CompareTo(group.Item1);
if (result == 0)
{
result = this.Item2.CompareTo(group.Item2);
}
}
return result;
}
#endregion
}
[Serializable]
public class ComparableTuple3EqualityComparer<TItem0, TItem1, TItem2>
: IEqualityComparer<ComparableTuple3<TItem0, TItem1, TItem2>>
where TItem0 : IComparable<TItem0>
where TItem1 : IComparable<TItem1>
where TItem2 : IComparable<TItem2>
{
#region Constructor
public ComparableTuple3EqualityComparer()
{
}
#endregion
public bool Equals(ComparableTuple3<TItem0, TItem1, TItem2> groupA,
ComparableTuple3<TItem0, TItem1, TItem2> groupB)
{
return ((groupA.Item0.Equals(groupB.Item0))
&& (groupA.Item1.Equals(groupB.Item1))
&& (groupA.Item2.Equals(groupB.Item2)));
}
public int GetHashCode(ComparableTuple3<TItem0, TItem1, TItem2> group)
{
int hash0 = group.Item0.GetHashCode();
int hash1 = group.Item1.GetHashCode();
int hash2 = group.Item2.GetHashCode();
int hash = 577 * hash0 + 599 * hash1 + 619 * hash2;
return hash.GetHashCode();
}
}
}
The Sparse3DMatrix Class in File Sparse3DMatrix.cs
using System;
using System.Collections.Generic;
namespace SparseCollections
{
[Serializable]
public class Sparse3DMatrix<TKey0, TKey1, TKey2, TValue> : IEnumerable<KeyValuePair<ComparableTuple3<TKey0, TKey1, TKey2>, TValue>>
where TKey0 : IComparable<TKey0>
where TKey1 : IComparable<TKey1>
where TKey2 : IComparable<TKey2>
{
private Dictionary<ComparableTuple3<TKey0, TKey1, TKey2>, TValue> m_dictionary;
public TValue DefaultValue
{
get;
set;
}
public int Count
{
get
{
return m_dictionary.Count;
}
}
#region Constructors
public Sparse3DMatrix()
{
InitializeDictionary();
}
public Sparse3DMatrix(TValue defaultValue)
{
InitializeDictionary();
DefaultValue = defaultValue;
}
public Sparse3DMatrix(Sparse3DMatrix<TKey0, TKey1, TKey2, TValue> sparse3DMatrix)
{
InitializeDictionary();
Initialize(sparse3DMatrix);
DefaultValue = sparse3DMatrix.DefaultValue;
}
#endregion
private void InitializeDictionary()
{
ComparableTuple3EqualityComparer<TKey0, TKey1, TKey2> equalityComparer = new ComparableTuple3EqualityComparer<TKey0, TKey1, TKey2>();
m_dictionary = new Dictionary<ComparableTuple3<TKey0, TKey1, TKey2>, TValue>(equalityComparer);
}
private void Initialize(Sparse3DMatrix<TKey0, TKey1, TKey2, TValue> sparse3DMatrix)
{
m_dictionary.Clear();
foreach (KeyValuePair<ComparableTuple3<TKey0, TKey1, TKey2>, TValue> pair in sparse3DMatrix)
{
ComparableTuple3<TKey0, TKey1, TKey2> newCombinedKey = new ComparableTuple3<TKey0, TKey1, TKey2>(pair.Key);
m_dictionary.Add(newCombinedKey, pair.Value);
}
}
public void CopyTo(Sparse3DMatrix<TKey0, TKey1, TKey2, TValue> sparse3DMatrix)
{
sparse3DMatrix.m_dictionary.Clear();
foreach (KeyValuePair<ComparableTuple3<TKey0, TKey1, TKey2>, TValue> pair in m_dictionary)
{
ComparableTuple3<TKey0, TKey1, TKey2> newCombinedKey = new ComparableTuple3<TKey0, TKey1, TKey2>(pair.Key);
sparse3DMatrix.m_dictionary.Add(newCombinedKey, pair.Value);
}
}
public TValue this[TKey0 key0, TKey1 key1, TKey2 key2]
{
get
{
TValue value;
if (!m_dictionary.TryGetValue(CombineKeys(key0, key1, key2), out value))
{
value = DefaultValue;
}
return value;
}
set
{
m_dictionary[CombineKeys(key0, key1, key2)] = value;
}
}
public bool ContainsKey(TKey0 key0, TKey1 key1, TKey2 key2)
{
return m_dictionary.ContainsKey(CombineKeys(key0, key1, key2));
}
public bool ContainsValue(TValue value)
{
return m_dictionary.ContainsValue(value);
}
public bool TryGetValue(TKey0 key0, TKey1 key1, TKey2 key2, out TValue value)
{
return m_dictionary.TryGetValue(CombineKeys(key0, key1, key2), out value);
}
public bool Remove(TKey0 key0, TKey1 key1, TKey2 key2)
{
return m_dictionary.Remove(CombineKeys(key0, key1, key2));
}
public void Clear()
{
m_dictionary.Clear();
}
public ComparableTuple3<TKey0, TKey1, TKey2> CombineKeys(TKey0 key0, TKey1 key1, TKey2 key2)
{
return new ComparableTuple3<TKey0, TKey1, TKey2>(key0, key1, key2);
}
public void SeparateCombinedKeys(ComparableTuple3<TKey0, TKey1, TKey2> combinedKey,
ref TKey0 key0,
ref TKey1 key1,
ref TKey2 key2)
{
key0 = combinedKey.Item0;
key1 = combinedKey.Item1;
key2 = combinedKey.Item2;
}
#region IEnumerable<KeyValuePair<ComparableTuple3<TKey0, TKey1, TKey2>, TValue>> Members
public IEnumerator<KeyValuePair<ComparableTuple3<TKey0, TKey1, TKey2>, TValue>> GetEnumerator()
{
return this.m_dictionary.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.m_dictionary.GetEnumerator();
}
#endregion
}
}
Points of Interest
I originally wrote the SparseArray
class. When I started to write the first sparse matrix class, I noted that all the sparse matrix classes would have a similar form. So, I wrote a code generator that wrote most of the code. I implemented the SparseMatrix8D
class first. Then it was easy to create the others. I still have the code generator in case I ever need a Sparse16DMatrix
!
Also, when I recently looked at Microsoft's Tuple classes online, I was surprised at how similar I had made the Group
classes, which again has been renamed to ComparableTuple
. I named the item property starting with Item0
, and Microsoft started at Item1
, but we essentially have exactly the same name for a property! I guess that is not surprising - "Item
" is a generic term for "something" and books describing properties often use the word "item".
History
- Initial post
- Based on feedback, I renamed the
Group<X>
classes to ComparableTuple<X>
. Added a 'using
' statement to the main program for the FileStream
instance. Updated the article accordingly and uploaded the new code. - Based on feedback, I removed the private set property method from the Count property of the SparseXDMatrix classes.
- Based on even good feeback from kornman00, I removed the incorrect and unneeded IEnumerator interface Move and Current propery methods from the sparse matrix classes. I update the article and uploaded the updated code.