This is a follow-up question for Generic Two Dimensional Data Plane with Manipulation Methods For C# and A SubPlane Method for Generic Two Dimensional Data Plane in C#. Based on iSR5's suggestion, in SubPlane
method, Array.Copy
is used instead of regular for
loop in order to improve performance.
The experimental implementation
The experimental implementation is as below.
[Serializable]
public class PlaneV3<T>
{
public int Width { get; }
public int Height { get; }
public T[,] Grid { get; set; }
public int Length => Width * Height;
public PlaneV3() : this(1, 1) { }
public PlaneV3(int width, int height)
{
Width = width;
Height = height;
Grid = new T[width, height];
}
public PlaneV3(PlaneV3<T> plane) : this(plane?.Grid) { }
public PlaneV3(T[,] sourceGrid)
{
if (sourceGrid is null)
{
throw new ArgumentNullException();
}
Width = sourceGrid.GetLength(0);
Height = sourceGrid.GetLength(1);
Grid = new T[Width, Height];
Array.Copy(sourceGrid, Grid, sourceGrid.Length);
}
public PlaneV3<T> ConcatenateHorizontal(PlaneV3<T> input)
{
if (input is null || input.Grid is null)
{
throw new ArgumentNullException();
}
if (this.Height.Equals(input.Height).Equals(false))
{
throw new ArgumentException();
}
var output = new PlaneV3<T>(this.Width + input.Width, this.Height);
for (int x = 0; x < this.Width; x++)
{
Array.Copy(this.Grid, x * this.Height, output.Grid, x * output.Height, this.Height);
}
for (int y = 0; y < this.Height; y++)
{
for (int x = 0; x < input.Width; x++)
{
output.Grid[this.Width + x, y] = input.Grid[x, y];
}
}
return output;
}
public PlaneV3<T> ConcatenateHorizontalInverse(PlaneV3<T> input)
{
return input.ConcatenateHorizontal(this);
}
public override bool Equals(object obj)
{
var input = obj as PlaneV3<T>;
// https://stackoverflow.com/a/12446807/6667035
return this.Grid.Rank == input.Grid.Rank &&
System.Linq.Enumerable.Range(0, this.Grid.Rank).All(dimension => this.Grid.GetLength(dimension) == input.Grid.GetLength(dimension)) &&
this.Grid.Cast<T>().SequenceEqual(input.Grid.Cast<T>());
}
public PlaneV3<T> SubPlane(int locationX, int locationY, int newWidth, int newHeight)
{
if (this.Grid == null)
{
return null;
}
PlaneV3<T> outputPlaneV3 = new PlaneV3<T>(newWidth, newHeight);
for (int y = 0; y < newHeight; y++)
{
Array.Copy(this.Grid, (y + locationY) * this.Width + locationX, outputPlaneV3.Grid, y * newWidth, newWidth);
}
return outputPlaneV3;
}
public override string ToString() => $"{nameof(PlaneV3<T>)}<{typeof(T).Name}>[{Width}, {Height}]";
public string ToDelimitedStringByHeightThenWidth(string separator = "\t")
{
return ToDelimitedString(Height, Width, separator, true);
}
public string ToDelimitedStringByWidthThenHeight(string separator = "\t")
{
return ToDelimitedString(Width, Height, separator, false);
}
private string ToDelimitedString(int outterCounter, int innerCounter, string separator, bool isHeightThenWidth)
{
var lines = new StringBuilder();
var columns = new StringBuilder();
for (int x = 0; x < outterCounter; x++)
{
var columnDelimiter = string.IsNullOrWhiteSpace(separator) ? "" : separator;
for (int y = 0; y < innerCounter; y++)
{
if (isHeightThenWidth)
{
columns.Append(columnDelimiter + Grid[y, x].ToString());
}
else
{
columns.Append(columnDelimiter + Grid[x, y].ToString());
}
if (columnDelimiter == string.Empty) // more readability
{
columnDelimiter = string.IsNullOrWhiteSpace(separator) ? "\t" : separator;
}
}
lines.AppendLine(columns.ToString());
columns.Clear(); // Clear and reuse it instead of initiating a new object.
}
return lines.ToString();
}
} // class
Test cases
The usage cases of PlaneV3
class above are as follows.
PlaneV3<string> planeV3_1 = new PlaneV3<string>(6, 6);
for (int j = 0; j < 6; j++)
{
for (int i = 0; i < 6; i++)
{
planeV3_1.Grid[i, j] = "(" + i + "," + j + ")";
}
}
Console.WriteLine(planeV3_1.SubPlane(1, 1, 3, 3).ToDelimitedStringByHeightThenWidth());
Console.WriteLine("");
Console.WriteLine(planeV3_1.SubPlane(1, 1, 3, 3).ToDelimitedStringByWidthThenHeight());
PlaneV3<string> planeV3_2 = new PlaneV3<string>(6, 6);
for (int j = 0; j < 6; j++)
{
for (int i = 0; i < 6; i++)
{
planeV3_2.Grid[i, j] = "(" + i + "," + j + ")";
}
}
Console.WriteLine(planeV3_1.Equals(planeV3_2).ToString());
All suggestions are welcome.
The summary information:
Which question it is a follow-up to?
Generic Two Dimensional Data Plane with Manipulation Methods For C# and
A SubPlane Method for Generic Two Dimensional Data Plane in C#
What changes has been made in the code since last question?
In
SubPlane
method,Array.Copy
is used instead of regularfor
loop.Trying to implement
ConcatenateHorizontal
based onArray.Copy
method.
Why a new review is being asked for?
If there is any possible improvement or any other potential defect, please let me know.