using System.Collections.Generic;
using System.Linq;
namespace ZeroLevel.DataStructures
{
///
/// Represents a Sparse matrix.
///
/// The type of the stored value.
public class SparseMatrix
{
///
/// Dictionary containing the row index as a key and as a value another dictionary
/// containing the column index as a key and the stored value as a value.
///
internal Dictionary> rows;
///
/// Dictionary containing the column index as a key and as a value another dictionary
/// containing the row index as a key and the stored value as a value.
///
internal Dictionary> cols;
///
/// Gets the maximum reached height of the sparse matrix.
///
public int Height { get; internal set; }
///
/// Gets the maximum reached width of the sparse matrix.
///
public int Width { get; internal set; }
///
/// Gets the number of items in the .
///
public int Count { get; internal set; }
///
/// Gets or sets an item in the sparse matrix. If there is no item on the given position
/// on get the default value of T is returned and on set the item is added to the matrix.
///
/// The zero-based row index of the item.
/// The zero-based column index of the item.
/// Returns the item in the sparse matrix. If there is no item on the given position the default value of T is returned instead.
public T this[int row, int col]
{
get
{
if (rows.ContainsKey(row))
{
if (rows[row].ContainsKey(col))
{
return rows[row][col];
}
}
//If there is no item on the given position return defaault value
return default(T);
}
set
{
if (row >= Height) Height = row + 1;
if (col >= Width) Width = col + 1;
//If no items on the current row we have to create a new dictionary
if (!rows.ContainsKey(row))
rows.Add(row, new Dictionary());
//If no items on the current col we have to create a new dictionary
if (!cols.ContainsKey(col))
cols.Add(col, new Dictionary());
rows[row][col] = value;
cols[col][row] = value;
Count++;
}
}
///
/// Creates a new instance of the class.
///
public SparseMatrix()
{
rows = new Dictionary>();
cols = new Dictionary>();
}
///
/// Creates a new instance of the class from the given two dimensional array.
///
/// The two dimensional array of items to add.
/// The item considered a zero item. All items from the array equal to the zero item won't be added to the matrix.
public SparseMatrix(T[,] array, T zeroItem)
{
rows = new Dictionary>();
cols = new Dictionary>();
for (int row = 0; row < array.GetLength(0); row++)
{
for (int col = 0; col < array.GetLength(1); col++)
{
if (!object.Equals(array[row, col], zeroItem))
this[row, col] = array[row, col];
}
}
}
///
/// Determines if there is an item on the given position.
///
/// The zero-based row index of the item.
/// The zero-based column index of the item.
/// Returns true if there is an item on the given position; otherwise false.
public bool IsCellEmpty(int row, int col)
{
if (rows.ContainsKey(row))
{
if (rows[row].ContainsKey(col))
{
return false;
}
}
return true;
}
///
/// Gets the items in the given row sorted by the column index as an
/// of with the key being the column index and the value being the item.
///
/// The zero-based row index.
/// Returns an of
/// with the key being the column index and the value being the item.
public IEnumerable> GetRowItems(int row)
{
if (rows.ContainsKey(row))
{
var sortedDict = new SortedDictionary(rows[row]);
foreach (var item in sortedDict)
{
yield return item;
}
}
}
///
/// Gets the items in the given column sorted by the row index as an
/// of with the key being the row index and the value being the item.
///
/// The zero-based column index.
/// Returns an of
/// with the key being the row index and the value being the item.
public IEnumerable> GetColumnItems(int col)
{
if (cols.ContainsKey(col))
{
var sortedDict = new SortedDictionary(cols[col]);
foreach (var item in sortedDict)
{
yield return item;
}
}
}
///
/// Gets non empty rows indexes sorted in ascending order.
///
/// Returns an of integers being row indexes sorted in ascending order.
public IEnumerable GetNonEmptyRows()
{
var sortedRows = new SortedSet(rows.Keys);
foreach (var row in sortedRows)
{
yield return row;
}
}
///
/// Gets non empty columns indexes sorted in ascending order.
///
/// Returns an of integers being column indexes sorted in ascending order.
public IEnumerable GetNonEmptyColumns()
{
var sortedCols = new SortedSet(cols.Keys);
foreach (var col in sortedCols)
{
yield return col;
}
}
///
/// Removes the item on the given position.
///
/// The zero-based row index.
/// The zero-based column index.
/// Returns true if item is removed successfully; otherwise false. Also returns false if the item is not found.
public bool Remove(int row, int col)
{
if (rows.ContainsKey(row))
{
if (rows[row].ContainsKey(col))
{
bool removedSuccessfully = true;
if (!rows[row].Remove(col) || !cols[col].Remove(row)) removedSuccessfully = false;
if (rows[row].Count == 0)
{
rows.Remove(row);
}
if (cols[col].Count == 0)
{
cols.Remove(col);
}
if (removedSuccessfully)
Count--;
return removedSuccessfully;
}
}
return false;
}
///
/// Removes all elements from the sparse matrix.
///
public void Clear()
{
rows.Clear();
cols.Clear();
Count = 0;
Height = 0;
Width = 0;
}
///
/// Updates the height and the width of the matrix. If no items were removed from the matrix the dimensions will be correct.
///
public void UpdateDimensions()
{
if (rows.Count == 0)
{
Height = 0;
Width = 0;
return;
}
Height = rows.Keys.Max() + 1;
Width = cols.Keys.Max() + 1;
}
}
}