[英]How can I loop through n-dimensional sparse matrix (created by own class)?
我有两节课
class CSparseMatrix:
{
public int NumberOfDimensions { get; set;}
public int DefaultNumber { get; set; }
List<int> dimensionsRanges = new List<int>(); // that's specify dimension of ranges, f.e. {100, 100, 100, 120..}
List<CSparseCell> cells = new List<CSparseCell>(); // contains only values different from default for this matrix
}
class CSparseCell {
public int Value { get; set; }
public List<int> coordinates = new List<int>();
}
问题是:如何循环遍历此CSparseMatrix
并输出所有具有以下格式值的范围: [0, 0, 0, 0] - *value*, [0, 0, 0, 1] - *value*, [0, 0, 0, 2] - *value*, ...[dimensionsRanges[0]-1, dimensionsRanges[1]-1, dimensionsRanges[2]-1, dimensionsRanges[3]-1] - *value*
所以通过所有范围并输出所有值(我们可以有任意数量的维度)。 这意味着在程序中我们必须输出矩阵的所有值,矩阵可以有任意数量的维度和范围可以不同。 但是我们不知道这个维度数是多少,所以不能使用 n 嵌套循环,实际上我不知道算法或方法如何迭代List<int> dimensionsRanges
所有值
我们从这个“矩阵”中得到特定值的方式是
public int GetValueFromCell(List<int> coordinate)
{
foreach(CSparseCell cell in cells)
{
if(cell.coordinates.All(coordinate.Contains)) {
return cell.Value;
}
}
return DefaultNumber;
}
既然您说您的矩阵很大, CSparseCell
通过将Value
查找推送到答案计算来避免返回CSparseCell
。
您创建一个方法来返回稀疏矩阵中的所有坐标,使用辅助方法来增加坐标。 注意:我将坐标增量方法更改为使用for
循环而不是do
这可能更容易理解 (?)。
void IncCoord(ref List<int> aCoord) { // ref not needed, just for documentation
for (var curDim = NumberOfDimensions - 1; curDim >= 0; --curDim) {
if (aCoord[curDim] == dimensionsRanges[curDim] - 1) // handle carry
aCoord[curDim] = 0;
else {
++aCoord[curDim];
break;
}
}
}
public IEnumerable<List<int>> AllCoords() {
var curCellCoord = Enumerable.Repeat(0, NumberOfDimensions).ToList();
var numCells = dimensionsRanges.Product();
for (int j1 = 0; j1 < numCells; ++j1) {
yield return curCellCoord.ToList();
IncCoord(ref curCellCoord);
}
}
现在您可以使用此方法获取所有Value
并且您可以随意格式化输出。 假设t
是CSparseMatrix
:
var ans = t.AllCoords().Select(c => $"[{c.Join(",")}] - {t.GetValueFromCell(c)}");
使用了几个辅助扩展方法:
public static class IEnumerableExt {
public static int Product(this IEnumerable<int> src) => src.Aggregate(1, (a,n) => a * n);
}
public static class StringExt {
public static string Join<T>(this IEnumerable<T> items, string sep) => String.Join(sep, items);
}
我会提出一些建议。 首先将坐标和值联系在一起会使事情复杂化。 把这两个分开会好得多。
其次,必须搜索整个数组才能找到单个单元格使其效率非常低下。 您可以从字典中创建一个简单的稀疏矩阵。 这根本不是最好的方法,但是由于您给出的未知关键要求,它至少比数组更好。 (如果键是 1..n,它真的是一个矩阵吗?)
这是一个例子。 首先,我们使坐标成为它们自己的类型。
readonly struct SparseCoord : IEquatable<SparseCoord>
{
public static SparseCoord ToCoordinate(params int[] coords)
{
return new SparseCoord(coords);
}
public SparseCoord(int[] c)
{
this.Coordinate = new int[c?.Length ?? 0];
if (null != c)
c.CopyTo(this.Coordinate, 0);
}
public int[] Coordinate { get; }
public bool Equals([AllowNull] SparseCoord other)
{
return Enumerable.SequenceEqual(this.Coordinate, other.Coordinate);
}
public override bool Equals(object obj)
{
if (obj is SparseCoord c)
return this.Equals(c);
return false;
}
public override int GetHashCode()
{
var hash = new HashCode();
foreach (var i in this.Coordinate)
hash.Add(i);
return hash.ToHashCode();
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append('(');
foreach (var i in this.Coordinate)
{
sb.Append(i);
sb.Append(',');
}
sb.Length = sb.Length - 1;
sb.Append(')');
return sb.ToString();
}
}
然后我们使用字典作为存储创建一个稀疏矩阵。 请注意,这显然是不完整的,因为无法部分或完全清除它,但这只是一个示例。
class SparseMatrix : IEnumerable<KeyValuePair<SparseCoord, int>>
{
Dictionary<SparseCoord, int> cells = new Dictionary<SparseCoord, int>();
public int this[SparseCoord coord]
{
get
{
if (this.cells.TryGetValue(coord, out var ret))
return ret;
return 0;
}
set
{
this.cells[coord] = value;
}
}
public IEnumerator<KeyValuePair<SparseCoord, int>> GetEnumerator()
{
return this.cells.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
然后您可以添加值并迭代内容:
static void Main(string[] _)
{
SparseMatrix matrix = new SparseMatrix();
matrix[SparseCoord.ToCoordinate(1, 2, 3)] = 1;
matrix[SparseCoord.ToCoordinate(5, 6, 7)] = 2;
foreach (var value in matrix)
Console.WriteLine(value);
}
最后,我要重申的是,如果您的矩阵真的像您在评论中所说的那样变得“大”,那么您应该花一些时间来研究一些众所周知的稀疏矩阵实现。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.