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; } } }