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();
...
Related
I'm looking for a smooth way to assign a Vector3D[] array using LINQ (and not looping). Is this possible?
I'm new to LINQ methods and I just started figuring out how to assign a whole array in a single line of code. For example:
double[] angle_in_radians = angle_in_degrees .Select(x => x / 180 * Math.PI).ToArray();
Suppose now I have the angle_in_radians array above and I want to use it in a vector3D array:
Vector3D[] example_vector = new Vector3D[n];
the way I solve the problem today is using a for loop:
for (int i = 0; i < n; i++)
{
example_vector[i] = new Vector3D(Math.Cos(angle_in_radians[i]), Math.Sin(angle_in_radians[i]), 0);
}
I can't really figure out how to use linq (if it's even possible). I want to somehow put:
angle_in_radians.Select(x => Math.Cos(x)).ToArray();
in all of the Vector3D X positions and the same with Y and Z.
You could replace a for loop by linq select like that :
var example_vectors = angle_in_radians.Select(x => new Vector3D(Math.Cos(x), Math.Sin(x), 0);
I want to perform a point-wise multiplication of a column array with each column array/vector in a given Matrix in C# using the Math.Net Numerics library.
There is little documentation on operations like this, so far I have the code below which doesn't work. I am trying to use LINQ as I prefer that over for loops. the problem I'm having with LINQ is I can't reassign my matrix when I try to enumerate each column of my matrix as a vector and do the PointwiseMultiply() method.
Matrix fitKernel is my matrix, and I want to point-wise multiply each column by the wF column array and update my matrix fitKernel using LINQ. fitKernel is 9 x 5 Matrix, and wF is a 9 x 1 double[] array that I convert to a Vector in the LINQ below.
Matrix<double> fitKernel = Matrix<double>.Build.DenseOfColumnArrays(c1, c2, c3, c4, ones);
double[] wF = Enumerable.Repeat(1.0, 9).ToArray();
fitKernel = fitKernel.EnumerateColumns()
.Select(v => v.PointwiseMultiply(Vector<double>.Build.DenseOfArray(wF)));
The above code using the EnumerateColumns() returns an IEnumerable of vectors, but when I try to assign the value to fitKernel it complains about assigning a type of Enumerable to a Matrix.
If you are going to write a for loop, you might as well write two.
// a = double[9];
// c = Matrix<double>
for (int ic = 0; ic < c.ColumnCount; ic++)
{
for (int ir = 0; ir < c.RowCount; ir++) c[ir, ic] = a[ir] * c[ir, ic];
}
It's probably the quickest and briefest solution, but I understand it doesn't tell the reader what you have in mind. OTOH, if you going to use an enumerator, it makes sense to let it control the loop.
var va = Vector<double>.Build.DenseOfArray(a);
var ColEnum = c.EnumerateColumnsIndexed() ;
foreach (System.Tuple<int,Vector<double>> col in ColEnum)
{
Vector<double> v = (Vector<double>)col.Item2.PointwiseMultiply((Vector<double>)va);
c.SetColumn(col.Item1, v);
}
The closest I could get to your first formulation is this:
var r = c.EnumerateColumns().Select(v => v.PointwiseMultiply(va));
int i = 0;
foreach (Vector ri in r) c.SetColumn(i++, ri);
The first line returns your new columns, but you still have to insert them into your Matrix. Note that we are trusting the enumerator to bring back the columns in their natural order. It's possible to reduce this to two lines using EnumerateColumnsIndexed. It requires more detail, but eliminates possible ambiguity about column order.
By the way, it does not work to combine the PointwiseMultiply and the SetColumn in one statement like this:
var r = c.EnumerateColumnsIndexed().Select((v) => c.SetColumn(v.Item1, v.Item2.PointwiseMultiply(va)));
apparently because SetColumn is void. If anyone has a workaround, please post it.
I think I figured it out but you have to use a for loop; doesn't seem to be any easy way using LINQ:
for (int i = 0; i < fitKernel.ColumnCount; i++)
{
var v = fitKernel.Column(i);
v = v.PointwiseMultiply(Vector<double>.Build.DenseOfArray(wF));
fitKernel.SetColumn(i, v);
}
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();
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.
I using Microsoft.Office.Interop.Excel I get returned a 2D array of type object[,] which contains double for elements. Note that the index lower bound is 1 instead of the default 0, but I can deal with that easily.
How can nicely convert the array into double[,] using .NET 3.5. (by nicely I mean concise, or compact).
Note that
double[] values_2 = values.Cast<double>().ToArray();
does work, but it flattens by array into a 1D structure.
object[,] src = new object[2, 3];
// Initialize src with test doubles.
src[0, 0] = 1.0;
src[0, 1] = 2.0;
src[0, 2] = 3.0;
src[1, 0] = 4.0;
src[1, 1] = 5.0;
src[1, 2] = 6.0;
double[,] dst = new double[src.GetLength(0), src.GetLength(1)];
Array.Copy(src, dst, src.Length);
I wouldn't say that there is one way that's faster than another so long as you don't do anything stupid. I'd say that, if you can, cast them when you access them rather than up front. Of course this depends on how you intend to access them. If you're going to index into the array more than once then the cost of unboxing might start to get too much. If you're only scanning the array once, then cast as you go.
This should work in most cases, but may throw an exception if you don't assign a conversion delegate.
public static TResult[,] Convert<TSource, TResult>(
this TSource[,] array, Func<TSource, TResult> conversion = null) {
if(array == null) throw new ArgumentNullException("array");
if (conversion == null) {
var resultType = typeof(TResult);
conversion = source => (TResult)System.Convert.ChangeType(source, resultType);
}
var width = array.GetLength(1);
var height = array.GetLength(0);
var result = new TResult[height, width];
for (int i = 0; i < height; ++i)
for (int j = 0; j < width; ++j)
result[i, j] = conversion(array[i, j]);
return result;
}
There are a couple problems here.
First, since double is not a reference type it must be boxed to be stored in an object[], so the only way to get to the values is to unbox the values into a double[] (copy copy).
The other problem is that in C#, arrays are covariant but not contravariant, you can assign an array to a reference of a more-derived type, not not to one of a less-derived type.
string[] strings = new string[10];
object[] objects = strings; // OK, covariant
string[] strings2 = objects; // not OK, contravariant
objects[0] = 10; // Compiles fine, runtime ArrayTypeMismatchException!
Array.Copy(src, dst, src.Length);
This code will get an error if any of the value in src is null.
Since in the above code src has a defined value it works fine.
If the value of src is dynamically set, and unfortunately if any of the value is null, the above code will not work because the value wont be copied successfully.