Multidimensional array, elements accessed by vector - c#

Is there any multidimensional array/collection/whatever datatype in .Net, elements of which can be accessed by vector (to vary number of dimensions easily)? Like this (C#):
var array = new Smth<double>(capacity: new int[] {xCap, yCap, zCap});
array[new int[] {x, y, z}] = 10.0;
To clarify: there is no need to explain how can I write such datatype manually.
Upodate:
I mean varying before creation, not after.
// 3D array
var array = new Smth<double>(capacity: new int[] {xCap, yCap, zCap});
array[new int[] {x, y, z}] = 10.0;
// 6D array
var array = new Smth<double>(capacity: new int[] {xCap, yCap, zCap, tCap, vCap, mCap});
array[new int[] {x, y, z, t, v, m}] = 10.0;

Although there are no off-the-shelf collections like that, you can easily emulate them using a Dictionary<int[],double> and a custom IEqualityComparerer<int[]>, like this:
class ArrayEq : IEqualityComparerer<int[]> {
public bool Equals(int[] a, int[] b) {
return a.SequenceEquals(b);
}
public int GetHashCode(int[] a) {
return a.Aggregate(0, (p, v) => 31*p + v);
}
}
With this equality comparer in hand, you can do this:
// The number of dimensions does not matter: if you pass a different number
// of dimensions, nothing bad is going to happen.
IDictionary<int[],double> array = new Dictionary<int[],double>(new ArrayEq());
array[new[] {1,2,3}] = 4.567;
array[new[] {1,2,-3}] = 7.654; // Negative indexes are OK
double x = array[new[] {1,2,3}]; // Get 4.567 back
If you need to have a certain capacity and a specific number of dimensions, you can modify the ArrayEq to be more strict at validating the data.
If you knew the number of dimensions at compile-time, you could use one of the Tuple<...> classes instead of arrays for potentially better performance. You could also define extension methods on multi-dimensional, say, double[,,,], arrays, to take vectors of indexes. Neither of these two approaches offers the same flexibility, though (which is a common trade-off -- better performance can often be gained by reducing flexibility).
EDIT: If you need to pre-allocate the storage and avoid storing your indexes, you could implement a multi-dimensional array yourself - like this:
class MultiD<T> {
private readonly T[] data;
private readonly int[] mul;
public MultiD(int[] dim) {
// Add some validation here:
// - Make sure dim has at least one dimension
// - Make sure that all dim's elements are positive
var size = dim.Aggregate(1, (p, v) => p * v);
data = new T[size];
mul = new int[dim.Length];
mul[0] = 1;
for (int i = 1; i < mul.Length; i++) {
mul[i] = mul[i - 1] * dim[i - 1];
}
}
private int GetIndex(IEnumerable<int> ind) {
return ind.Zip(mul, (a, b) => a*b).Sum();
}
public T this[int[] index] {
get { return data[GetIndex(index)]; }
set { data[GetIndex(index)] = value; }
}
}
This is a straightforward implementation of row-major indexing scheme that uses generics.

Related

Create a 2D Matrix X[][] with letters on X axis and numbers on Y Axis

I am trying to create a 2D matrix like given below.
I am not able to find a way, please help me out.
A pseudo code would be very helpful.
Normal x[3][5] 2D matrix :
[00][01][02][03][04]
[10][11][12][13][14]
[20][21][22][23][24]
What I want to create is x[C][5]
[A0][A1][A2][A3][A4]
[B0][B1][B2][B3][B4]
[C0][C1][C2][C3][C4]
This isn't quite the syntax you were looking for, but I think it'll suit your needs. In order to get the behavior you want, you'll need to create a class that stores a 2D matrix and overloads the [] operator to accept a char instead of an int
public class Matrix<T> {
private T[,] arr;
public Matrix(int x, int y) {
arr = new T[x, y];
}
public T this[char c, int i] {
get { return arr[c - 'A', i]; }
set { arr[c - 'A', i] = value; }
}
}
As you can see, the code is actually pretty simple. It takes advantage of the fact that the char datatype holds the ASCII value of its letter. By subtracting away 'A', we can use 'A' as 0, 'B' as 1, etc. Then you can call your Matrix using characters like so:
Matrix<int> m = new Matrix<int>(3,4); // Creates a 3 x 4 matrix of ints
m['B',3] = 4; // m[1,3] = 4
EDIT
If you wanted to, you could also modify the constructor to accept a char
public Matrix(char x, int y) {
arr = new T[x - 'A' + 1, y];
}
Note that the character you use to initialize, like an integer initializer for an array, is the number of entries and thus one greater than the highest index.
Matrix<int> m = new Matrix<int>('C',4); // Creates a 3 x 4 matrix of ints
m['B',3] = 4; // m[1,3] = 4

faster algorithm or technique for building sparse arrays in c#

I have a matrix-building problem. To build the matrix (for a 3rd party package), I need to do it row-by-row by passing a double[] array to the 3rd-party object. Here's my problem: I have a list of objects that represent paths on a graph. Each object is a path with a 'source' property (string) and a 'destination' property (also string). I need to build a 1-dimensional array where all the elements are 0 except where the source property is equal to a given name. The given name will occur multiple times in the path list. Here's my function for building the sparse array:
static double[] GetNodeSrcRow3(string nodeName)
{
double[] r = new double[cpaths.Count ];
for (int i = 1; i < cpaths.Count; i++)
{
if (cpaths[i].src == nodeName) r[i] = 1;
}
return r;
}
Now I need to call this function about 200k times with different names. The function itself takes between 0.05 and 0.1 seconds (timed with Stopwatch). As you can imagine, if we take the best possible case of 0.05 seconds * 200k calls = 10,000 seconds = 2.7 hours which is too long. The object 'cpaths' contains about 200k objects.
Can someone think of a way to accomplish this in a faster way?
I can't see the rest of your code, but I suspect most of the time is spent allocating and garbage collecting all the arrays. Assuming the size of cpaths doesn't change, you can reuse the same array.
private static double[] NodeSourceRow == null;
private static List<int> LastSetIndices = new List<int>();
static double[] GetNodeSrcRow3(string nodeName) {
// create new array *only* on the first call
NodeSourceRow = NodeSourceRow ?? new double[cpaths.Count];
// reset all elements to 0
foreach(int i in LastSetIndices) NodeSourceRow[i] = 0;
LastSetIndices.Clear();
// set the 1s
for (int i = 1; i < cpaths.Count; i++) {
if (cpaths[i].src == nodeName) {
NodeSourceRow[i] = 1;
LastSetIndices.Add(i);
}
}
// tada!!
return NodeSourceRow;
}
One drawback potential drawback would be if you need all the arrays to used at the same time, they will always have identical contents. But if you only use one at a time, this should be much faster.
if cpaths is normal list then that's not suitable for your case. you need a dictionary of src to list of indexes. like Dictionary<string, List<int>>.
then you can fill sparse array with random access. I would also suggest you to use Sparse list implementation for efficient memory usage rather than using memory inefficient double[]. a good implementation is SparseAList. (written by David Piepgrass)
Before generating your sparse lists, you should convert your cpaths list into a suitable dictionary, this step may take a little long (up to few seconds), but after that you will generate your sparse lists super fast.
public static Dictionary<string, List<int>> _dictionary;
public static void CacheIndexes()
{
_dictionary = cpaths.Select((x, i) => new { index = i, value = x })
.GroupBy(x => x.value.src)
.ToDictionary(x => x.Key, x => x.Select(a => a.index).ToList());
}
you should call CacheIndexes before starting to generate your sparse arrays.
public static double[] GetNodeSrcRow3(string nodeName)
{
double[] r = new double[cpaths.Count];
List<int> indexes;
if(!_dictionary.TryGetValue(nodeName, out indexes)) return r;
foreach(var index in indexes) r[index] = 1;
return r;
}
Note that if you use SparseAList it will occupy very small space. for example if double array is 10K length and has only one index set in it, with SparseAList you will have virtually 10K items, but in fact there is only one item stored in memory. its not hard to use that collection, I suggest you to give it a try.
same code using SparseAList
public static SparseAList<double> GetNodeSrcRow3(string nodeName)
{
SparseAList<double> r = new SparseAList<double>();
r.InsertSpace(0, cpaths.Count); // allocates zero memory.
List<int> indexes;
if(!_dictionary.TryGetValue(nodeName, out indexes)) return r;
foreach(var index in indexes) r[index] = 1;
return r;
}
You could make use of multi-threading using the TPL's Parallel.For method.
static double[] GetNodeSrcRow3(string nodeName)
{
double[] r = new double[cpaths.Count];
Parallel.For(1, cpaths.Count, (i, state) =>
{
if (cpaths[i].src == nodeName) r[i] = 1;
});
return r;
}
Fantastic Answers!
If I may add some, to the already great examples:
System.Numerics.Tensors.SparseTensor<double> GetNodeSrcRow3(string text)
{
// A quick NuGet System.Numerics.Tensors Install:
System.Numerics.Tensors.SparseTensor<double> SparseTensor = new System.Numerics.Tensors.SparseTensor<double>(new int[] { cpaths.Count }, true, 1);
Parallel.For(1, cpaths.Count, (i, state) =>
{
if (cpaths[i].src == nodeName) SparseTensor[i] = 1.0D;
});
return SparseTensor;
}
System.Numerics is optimised hugely, also uses hardware acceleration. It is also Threadsafe. At least from what I have read about it.
For Speed and scalability, a small bit of code that could make all the difference.

Finding n number of closest points in a list

C# beginner here, working with Grasshopper for Rhino so some object types are a little strange.
I am currently trying to find n number of closest points within a list to a given point. I am able to find the closest point using the following function, but cannot adapt it to retrieve multiple closest points.
public Vec3D ClosestPoint(Vec3D a, List<Vec3D>points){
List<float> distanceList = new List<float>();
for (int i = 0; i < points.Count(); i++){
float distanceFloat = a.distanceTo(points[i]);
distanceList.Add(distanceFloat);
}
int smallestIndex = distanceList.IndexOf(distanceList.Min());
return points[smallestIndex];
}
How would I adapt this code for the below function, where n is how many closest points to find?
public Vec3D ClosestPoints(Vec3D a, List<Vec3D>points, int n){
}
You can use Linq to get that result:
public IEnumerable<Vec3D> ClosestPoints(Vec3D a, List<Vec3D>points, int n) =>
points.Select(point => new
{
point = point,
distance = a.distanceTo(point)
}).
OrderBy(x = x.distance).
Take(n).
Select(x => x.point);
Note that in this case, the other method becomes:
public Vec3D ClosestPoint(Vec3D a, List<Vec3D>points) =>
ClosestPoints(a, points, 1).FirstOrDefault();

Convert members of struct in a list to array

To process data from a log file, I read the data into a list.
When I tried to convert from the list to an array for the graphing routine, I ran into trouble.
For the sake of this discussion, let's say the log file contains three values* - x, y and theta. In the routine that does file I/O, I read the three values, assign them to a struct and add the struct to PostureList.
The plotting routine, wants the x, y and theta to be in individual arrays. My thought was to use the ToArray() method to do the conversion but when I tried the syntax below, I got an error - see error in comment below. I have an alternate approach to do the conversion but wanted to get advice on better approaches.
I'm very new to C#. Thanks in advance for your help.
NOTE: * In reality, the log file contains many different pieces of information that have varying payload sizes.
struct PostureStruct
{
public double x;
public double y;
public double theta;
};
List<PostureStruct> PostureList = new List<PostureStruct>();
private void PlotPostureList()
{
double[] xValue = new double[PostureList.Count()];
double[] yValue = new double[PostureList.Count()];
double[] thetaValue = new double[PostureList.Count()];
// This syntax gives an error:
// Error 1 'System.Collections.Generic.List<TestNameSpace.Test.PostureStruct>'
// does not contain a definition for 'x' and no extension method 'x' accepting a first
// argument of type 'System.Collections.Generic.List<TestNameSpace.Test.PostureStruct>'
// could be found (are you missing a using directive or an assembly reference?)
xValue = PostureList.x.ToArray();
yValue = PostureList.y.ToArray();
thetaValue = PostureList.theta.ToArray();
// I could replace the statements above with something like this but I was wondering if
// if there was a better way or if I had some basic mistake in the ToArray() syntax.
for (int i = 0; i < PostureList.Count(); i++)
{
xValue[i] = PostureList[i].x;
yValue[i] = PostureList[i].y;
thetaValue[i] = PostureList[i].theta;
}
return;
}
The ToArray extension method can only be used on IEnumerables. To transform an IEnumerable, for example from your struct to a single value, you can use the Select extension method.
var xValues = PostureList.Select(item => item.x).ToArray();
var yValues = PostureList.Select(item => item.y).ToArray();
var thetaValues = PostureList.Select(item => item.theta).ToArray();
You don't need to define the size of the arrays or create them with new, the extension method will take care of that.
you are trying to reference x directly on list.
PostureList.y
you need to do it on specific member like
PostureList[0].y
i guess you need to select all the x from your list. For that you can do this
xValue = PostureList.Select(x => x.x).ToArray();
You can use this way to convert your List<PostureStruct> to individual arrays:
double[] xValue = PostureList.Select(a => a.x).ToArray();
double[] yValue = PostureList.Select(a => a.y).ToArray();
double[] thetaValue = PostureList.Select(a => a.theta).ToArray();
This is all you have to do and the arrays will have the right size (same as the list's lenght).
You can either loop through the list:
double[] xValue = new double[PostureList.Count()];
double[] yValue = new double[PostureList.Count()];
double[] thetaValue = new double[PostureList.Count()];
foreach (int i = 0; i < PostureList.Count; ++i) {
xValue[i] = PostureList[i].x;
yValue[i] = PostureList[i].y;
thetaValue[i] = PostureList[i].theta;
}
...
Or use Linq, but in different manner:
double[] xValue = PostureList.Select(item => item.x).ToArray();
double[] yValue = PostureList.Select(item => item.y).ToArray();
double[] thetaValue = PostureList.Select(item => item.theta).ToArray();
...

Linq to find pair of points with longest length?

I have the following code:
foreach (Tuple<Point, Point> pair in pointsCollection)
{
var points = new List<Point>()
{
pair.Value1,
pair.Value2
};
}
Within this foreach, I would like to be able to determine which pair of points has the most significant length between the coordinates for each point within the pair.
So, let's say that points are made up of the following pairs:
(1) var points = new List<Point>()
{
new Point(0,100),
new Point(100,100)
};
(2) var points = new List<Point>()
{
new Point(150,100),
new Point(200,100)
};
So I have two sets of pairs, mentioned above. They both will plot a horizontal line. I am interested in knowing what the best approach would be to find the pair of points that have the greatest distance between, them, whether it is vertically or horizontally. In the two examples above, the first pair of points has a difference of 100 between the X coordinate, so that would be the point with the most significant difference. But if I have a collection of pairs of points, where some points will plot a vertical line, some points will plot a horizontal line, what would be the best approach for retrieving the pair from the set of points whose difference, again vertically or horizontally, is the greatest among all of the points in the collection?
Thanks!
Chris
Use OrderBy to create an ordering based on your criteria, then select the first one. In this case order by the maximum absolute difference between the horizontal and vertical components in descending order.
EDIT: Actually, I think you should be doing this on the Tuples themselves, right? I'll work on adapting the example to that.
First, let's add an extension for Tuple<Point,Point> to calculate it's length.
public static class TupleExtensions
{
public static double Length( this Tuple<Point,Point> tuple )
{
var first = tuple.Item1;
var second = tuple.Item2;
double deltaX = first.X - second.X;
double deltaY = first.y - second.Y;
return Math.Sqrt( deltaX * deltaX + deltaY * deltaY );
}
}
Now we can order the tuples by their length
var max = pointCollection.OrderByDescending( t => t.Length() )
.FirstOrDefault();
Note: it is faster to just iterate over the collection and keep track of the maximum rather than sorting/selecting with LINQ.
Tuple<Point,Point> max = null;
foreach (var tuple in pointCollection)
{
if (max == null || tuple.Length() > max.Length())
{
max = tuple;
}
}
Obviously, this could be refactored to an IEnumerable extension if you used it in more than one place.
You'll need a function probably using the pythagorean theorem to calculate the distances
a^2 + b^2 = c^2
Where a would be the difference in Point.X, b would be the difference in Point.Y, and c would be your distance. And once that function has been written, then you can go to LINQ and order on the results.
Here's what I did. (Note: I do not have C# 4, so it's not apples to apples
private double GetDistance(Point a, Point b)
{
return Math.Pow(Math.Pow(Math.Abs(a.X - b.X), 2) + Math.Pow(Math.Abs(a.Y - b.Y), 2), 0.5);
}
You can turn that into an anonymous method or Func if you prefer, obviously.
var query = pointlistCollection.OrderByDescending(pair => GetDistance(pair[0], pair[1])).First();
Where pointlistCollection is a List<List<Point>>, each inner list having two items. Quick example, but it works.
List<List<Point>> pointlistCollection
= new List<List<Point>>()
{
new List<Point>() { new Point(0,0), new Point(3,4)},
new List<Point>() { new Point(5,5), new Point (3,7)}
};
***Here is my GetDistance function in Func form.
Func<Point, Point, double> getDistance
= (a, b)
=> Math.Pow(Math.Pow(Math.Abs(a.X - b.X), 2) + Math.Pow(Math.Abs(a.Y - b.Y), 2), 0.5);
var query = pointlistCollection.OrderByDescending(pair => getDistance(pair[0], pair[1])).First();
As commented above: Don't sort the list in order to get a maximum.
public static double Norm(Point x, Point y)
{
return Math.Sqrt(Math.Pow(x.X - y.X, 2) + Math.Pow(x.Y - y.Y, 2));
}
Max() needs only O(n) instead of O(n*log n)
pointsCollection.Max(t => Norm(t.Item1, t.Item2));
tvanfosson's answer is good, however I would like to suggest a slight improvement : you don't actually need to sort the collection to find the max, you just have to enumerate the collection and keep track of the maximum value. Since it's a very common scenario, I wrote an extension method to handle it :
public static class EnumerableExtensions
{
public static T WithMax<T, TValue>(this IEnumerable<T> source, Func<T, TValue> selector)
{
var max = default(TValue);
var withMax = default(T);
bool first = true;
foreach (var item in source)
{
var value = selector(item);
int compare = Comparer<TValue>.Default.Compare(value, max);
if (compare > 0 || first)
{
max = value;
withMax = item;
}
first = false;
}
return withMax;
}
}
You can then do something like that :
Tuple<Point, Point> max = pointCollection.WithMax(t => t.Length());

Categories