I have a linear array which I need to reshape as of a stack of 2D data. In this particular case, the stack only contains one element so the output should be an array with dimensions (height, width, 1).
This is related to a previous question, where I was asking about the same operation in the other direction (3D to 1D).
What is the fastest way to map this data to a 3D array?
I was planning to take the following approach:
public static byte[, ,] ToBuffer3D<TDepth>(this byte[] buffer, int w, int h)
{
byte[, ,] buff3D = new byte[h, w, 1];
for (int i = 0; i < buffer.Length; i++)
{
buff3D[(int)Math.Floor(i / (double)w), i % w, 0] = buffer[i];
}
return buff3D;
}
But it seems like it might be possible to take advantage of how the data is already stored in memory to copy more than one element at a time. Is there some other mapping approach that could be employed in C#?
This is likely to be somewhat faster:
public static byte[,,] ToBuffer3Da(this byte[] buffer, int w, int h)
{
byte[,,] buff3D = new byte[h, w, 1];
Buffer.BlockCopy(buffer, 0, buff3D, 0, h*w);
return buff3D;
}
if you use the base class and implementation defined below, you have a class that supports both linear and dimensional indexing at the same time. No conversion or copying is necessary.
Use it like this,
var matrix = new DecomposedMatrix<byte>(10, 10, 10)
foreach(var b int matrix)
{
...
}
for (var i = 0; i < matrix.Count; i++)
{
...
var item = matrix[i];
...
}
for (var x = 0; x < matrix.H; x++)
for (var y = 0; y < matrix.W; y++)
for (var z = 0; z < matrix.D; z++)
{
...
var item = matrix[x, y, z];
...
}
classes follow ...
public abstract class DecomposedMatrix
{
private readonly int h;
private readonly int w;
private readonly int d;
protected DecomposedMatrix(int h, int w, int d)
{
this.h = h;
this.w = w;
this.d = d;
}
public int W
{
get
{
return this.w;
}
}
public int D
{
get
{
return this.d;
}
}
public int H
{
get
{
return this.h;
}
}
protected int DereferenceCoordinates(int x, int y, int z)
{
if (x >= this.H || y >= this.W || z >= this.D)
{
throw new IndexOutOfRangeException();
}
if (x < 0 || y < 0 || z < 0)
{
throw new IndexOutOfRangeException();
}
return z + (y * this.D) + (x * this.W * this.D);
}
}
and the implementation
public class DecomposedMatrix<T> : DecomposedMatrix, IReadOnlyList<T>
{
private readonly IList<T> data;
public DecomposedMatrix(int h, int w, int d)
: base(h, w, d)
{
this.data = new T[h * w * d];
}
public T this[int index]
{
get
{
return this.data[index];
}
set
{
this.data[index] = value;
}
}
public T this[int x, int y, int z]
{
get
{
return this.data[this.DereferenceCoordinates(x, y, z)];
}
set
{
this.data[this.DereferenceCoordinates(x, y, z)] = value;
}
}
public int Count
{
get
{
return this.data.Count;
}
}
public IEnumerator<T> GetEnumerator()
{
return this.data.GetEnumerator();
}
public IEnumerator IEnumerable.GetEnumerator()
{
return this.data.GetEnumerator();
}
}
Related
I have a simple class point
public class point
{
private double X;
private double Y;
public double x
{
get { return X; }
set { X = value; }
}
public double y
{
get { return Y; }
set { Y = value; }
}
public point() { }
public point(double _x , double _y)
{
x = _x;
y = _y;
}
}
and I'm trying to use this loop to get unique values
for (int i = 0; i < dim.Count; i++)
{
if (dimO[i].x == dim[i].x && dimO[i].y == dim[i].y)
{
continue;
}
else
{
dimO.Add(dim[i]);
}
}
but I got an " out of index" exception .. what's wrong here?
You should override Equals and GetHashCode if you want to compare a point by its x and y.
public override bool Equals(object obj)
{
var point2 = obj as Point;
return point2 != null && point2.x == x && point2.y == y;
}
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + X.GetHashCode();
hash = hash * 23 + Y.GetHashCode();
return hash;
}
}
I take the hash code function here.
Now you could have a list of unique points by using
var dim0 = (new HashSet(dim)).ToList();
// linq
var dim0 = dim.Distinct().ToList();
Or if you want to use for loop
var dim0 = new List<Point>();
foreach(var p in dim){
if(!dim0.Contains(p)){
dim0.Add(p);
}
}
Your solution is not working because dim0 does not initially have any point.
I hope you have a nice day, so here is my problem: I'm trying to find the middle point of most populated positions (X/Y) on a map but i'm stuck and i can't find a good and effective way to do it.
To find this position i've access to an collection of entities (and these entities have a Position property (which is a Vector2D) and map size
public readonly struct Vector2D
{
private static readonly double Sqrt = Math.Sqrt(2);
private static readonly Random Random = new Random();
public static Vector2D Zero { get; } = new Vector2D();
public int X { get; }
public int Y { get; }
public Vector2D(int x, int y)
{
X = x;
Y = y;
}
public Vector2D GetDistanceTo(Vector2D vector2D) => new Vector2D(Math.Abs(vector2D.X - X), Math.Abs(vector2D.Y - Y));
public int GetDistance(Vector2D destination)
{
int x = Math.Abs(X - destination.X);
int y = Math.Abs(Y - destination.Y);
int min = Math.Min(x, y);
int max = Math.Max(x, y);
return (int)(min * Sqrt + max - min);
}
public bool IsInRange(Vector2D position, int range)
{
int dx = Math.Abs(X - position.X);
int dy = Math.Abs(Y - position.Y);
return dx <= range && dy <= range && dx + dy <= range + range / 2;
}
public override string ToString() => $"{X}/{Y}";
}
That's the only thing i've tried
public Vector2D FindMostPopulatedPosition()
{
IEnumerable<Vector2D> positions = Entities.Select(x => x.Position);
return new Vector2D((int)positions.Average(x => x.X), (int)positions.Average(x => x.Y));
}
Here is some example images
Red dot: All entities
Blue dot: The position i'm looking for
Thanks for reading (and for your help)
I want to implement my own Priority Queue in C# using the naive approach. I need to use PQ for edges in a graph to implement Prims algorithm. Here is what I've done so far:
public class Edge
{
private int v; // one vertex
private int w; // the other vertex
private int weight; // edge weight
public Edge(int v0, int w0, int weight0)
{
v = v0;
w = w0;
weight = weight0;
}
public Edge()
{
v = 0;
w = 0;
weight = 0;
}
public int get_weight()
{
return weight;
}
public int either()
{
return v;
}
public int the_other(int vertex)
{
if (vertex == v) return w;
else return v;
}
public int compareTo(Edge that)
{
if (this.get_weight() < that.get_weight()) return -1;
if (this.get_weight() < that.get_weight()) return 1;
else return 0;
}
public string to_str()
{
string s = v.ToString() + " " + weight.ToString() + " " + w.ToString() + '\n';
return s;
}
}
public class MyPriorityQueue_Edge
{
private List<Edge> q = new List<Edge>();
int size;
public MyPriorityQueue_Edge()
{
size = 0;
}
public void insert(Edge e)
{
q.Add(e);
size++;
}
Edge Min()
{
int min_weight = 1000;
Edge min_edge = new Edge();
foreach(Edge e in q)
if(e.get_weight()< min_weight)
min_edge = e;
return min_edge;
}
public Edge delmin()
{
Edge e = q.Min();
q.Remove(e);
size--;
return e;
}
public bool is_empty()
{
if (size == 0) return true;
else return false;
}
}
When I compile it the compiler points to this line:
Edge e = q.Min();
And says that I did not work on the exception "System.Argument.Exception". How can I fix this?
From MSDN Enumerable.Min<TSource> Method (IEnumerable<TSource>)
If type TSource implements IComparable<T>, this method uses that implementation to compare values. Otherwise, if type TSource implements IComparable, that implementation is used to compare values.
You need to implement IComparable interface in your Edge class.
public class Edge : IComparable
Then add a CompareTo() method. Something like
public int CompareTo(object obj)
{
if (obj is Edge)
{
Edge other = (Edge)obj;
return this.compareTo(other); // you already implemented this in your Edge class
}
else
{
throw new InvalidOperationException();
}
}
I have a class, Matrix, and try to overload the + operator in this class.
The problem is in matrix1 and matrix2, I can't create a clone of this to object. I already even tried to make it using a few for loops but it throws an OutOfMemoryException.
public static Matrix<T> operator +(Matrix<T> matrix1, Matrix<T> matrix2)
{
Matrix<T> m1 = matrix1;
Matrix<T> m2 = matrix2;
Matrix<T> result = new Matrix<T>();
if (m1.Cols != m2.Cols || m1.Rows != m2.Rows)
{
if (m1.Rows > m2.Rows)
m2.Rows = m1.Rows;
else if (m1.Rows < m2.Rows)
m1.Rows = m2.Rows;
if (m1.Cols > m2.Cols)
m2.Cols = m1.Cols;
else if (m1.Cols < m2.Cols)
m1.Cols = m2.Cols;
}
for (int i = 0; i < m1.Rows; i++)
{
result.Add(new List<T>());
for (int j = 0; j < m1.Cols; j++)
{
result[i].Add(new T());
result[i][j] = Sum<T>(m1[i, j], m2[i, j]);
}
}
result.Cols = m1.Cols;
return result;
}
I done it in this way
public static List<List<T>> ListClone(List<List<T>> data)
{
var new_data= new List<List<T>>();
foreach (var list in data)
{
new_data.Add(ListClone(list));
}
return new_data;
}
public static List<T> ListClone(List<T> list)
{
var new_list = new List<T>();
foreach(var i in list)
{
new_list.Add((T)i);
}
return new_list;
}
public static Matrix<T> operator +(Matrix<T> matrix1, Matrix<T> matrix2)
{
var m1 = new Matrix<T>();
m1.Cols = matrix1.Cols;
m1.Rows = matrix1.Rows;
m1.Data = ListClone(matrix1.data);
var m2 = new Matrix<T>();
m2.Cols = matrix2.Cols;
m2.Rows = matrix2.Rows;
m2.Data = ListClone(matrix2.data);
Matrix<T> result = new Matrix<T>();
if (m1.Cols!=m2.Cols || m1.Rows!=m2.Rows)
{
if (m1.Rows > m2.Rows)
m2.Rows = m1.Rows;
else if (m1.Rows < m2.Rows)
m1.Rows = m2.Rows;
if (m1.Cols > m2.Cols)
m2.Cols = m1.Cols;
else if (m1.Cols < m2.Cols)
m1.Cols = m2.Cols;
}
for (int i = 0; i < m1.Rows; i++)
{
result.Add(new List<T>());
for (int j = 0; j < m1.Cols; j++)
{
result[i].Add(new T());
result[i][j] = Sum<T>(m1[i, j], m2[i, j]);
}
}
result.Cols = m1.Cols;
return result;
}
but maybe someone have better idiea how to do this easer?
First up, don't make a matrix using a List<List<T>>. Just use a List<T> and figure out the access operators yourself.
Second, why do you allow the user to set the Row or Column count? Make the matrix immutable and fix the sizes at construction.
public class Matrix<T> : ICloneable
where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
{
private readonly int _rows;
private readonly int _columns;
private readonly IList<T> _data;
public Matrix(int rows, int columns)
{
_rows = rows;
_columns = columns;
_data = new List<T>(Rows * Columns);
}
private Matrix(int rows, int columns, IList<T> data)
{
_rows = rows;
_columns = columns;
_data = new List<T>(data);
}
public int Rows
{
get { return _rows; }
}
public int Columns
{
get { return _columns; }
}
public T Element(int row, int column)
{
return _data[row * column];
}
public object Clone()
{
return new Matrix<T>(Rows, Columns, _data);
}
}
The other operators I leave as an exercise
I'm trying to sort an ArrayList of strings (not in int).
Given:
f.e.
[0] 23,24
[1] 12,33
[2] 37,11
Arraylist.Sort should give back (sorted by the last number ascending):
[0] 37,11
[1] 23,24
[2] 12,33
Having this so far:
public class Point
{
public int i, j;
public Point(int i, int j)
{this.i = i; this.j = j;}
public string ToString()
{return i + "," + j;}
}
public class SList
{
public static void Main()
{
ArrayList Slist = new ArrayList();
Random Generate = new Random();
for (int i = 0; i < 3; i++)
{
Point p = new Point(Generate.Next(40), Generate.Next(40));
Slist.Add(p.ToString());
}
Slist.Sort();
}
}
I'm not 100% sure if you have an array of strings or if they are split already, but you can create a custom comparer and do something like this perhaps. Make clearer what you want so that people can help you better.
public class MyCustomComparer : IComparer<string>
{
public int Compare(string x, string y)
{
var xIntValues = x.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
var yIntValues = y.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
for(var i = 0; i < Math.Min(xIntValues.Count(), yIntValues.Count()); ++i)
if (xIntValues[i] != yIntValues[i])
return xIntValues[i] - yIntValues[i];
return xIntValues.Count() - yIntValues.Count();
}
}
Then use it like this where your array elements contain strings like "37, 11"
Array.Sort(myArray, MyCustomComparer);
Sort of odd to be using an ArrayList after c# 1.0, but if you have one for legacy reasons, you can create your own non-generic custom comparer, like so:
public class CustomComparer : IComparer<string>, IComparer {
#region IComparer<string> Members
int? ExtractNumber(string str)
{
int index = str.LastIndexOf(',');
if (index < 0)
return null;
var subStr = str.Substring(index+1);
int result;
if (int.TryParse(subStr, out result))
return result;
return null;
}
// Return x - y
public int Compare(string x, string y)
{
#if false
Given: f.e.
[0] 23,24
[1] 12,33
[2] 37,11
Arraylist.Sort should give back (sorted by the last number ascending):
[0] 37,11
[1] 23,24
[2] 12,33
#endif
var xVal = ExtractNumber(x);
var yVal = ExtractNumber(y);
if (!xVal.HasValue && !yVal.HasValue)
return x.CompareTo(y);
else if (!xVal.HasValue)
return 1;
else if (!yVal.HasValue)
return -1;
int cmp = xVal.Value.CompareTo(yVal.Value);
if (cmp != 0)
return cmp;
return x.CompareTo(y);
}
#endregion
#region IComparer Members
public int Compare(object x, object y)
{
if (object.ReferenceEquals(x, y))
return 0;
string xStr = x as string;
string yStr = y as string;
if (xStr == null && yStr == null)
return 0; // NO IDEA
else if (xStr == null)
return 1;
else if (yStr == null)
return -1;
else return Compare(xStr, yStr);
}
#endregion
}
The following code implements IComparable on your class. It sorts on y in ascending order:
public class Point : IComparable<Point>
{
public int x;
public int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
public string ToString()
{
return x + "," + y;
}
public int CompareTo(Point other)
{
return this.y.CompareTo(other.y);
}
}
You can now use ArrayList.Sort() to achieve the order you need.
The easiest way to do this would be by stepping away from your non-generic list:
var sortedList = list.Cast<string>().OrderBy(x => x.Split(',')[1]);
The code is self-explanatory.
Using this as input:
var list = new ArrayList();
list.Add("23,24");
list.Add("12,33");
list.Add("37,11");
Yields this as output:
37,11
23,24
12,33