Pass slice of a value-array to a function as reference - c#

I need to call a function (Matrix.TransformPoints) which has an array of Point (PointF) as a parameter. Unfortunately I only want to apply that function to a slice of that array and I cannot find a function which returns a slice using the original original array as a backing.
It will always be a new array and as both types are structs, it'll copy the values of the Point. It would be nice if it would support Span<T>, as that would do the trick.
For testing, I've been writing this example. I've added a DoSpan function, because then I could verify that DoArray(Span.ToArray()) doesn't work while DoSpan(Span) does. Only when passing the original array to DoArray (or using DoSpan), it'll actually change the values from the original array.
// Same parameters as Matrix.TransformPoints
public static void DoArray(Point[] points)
{
for (int i = 0; i < points.Length; i++)
{
points[i].X++;
}
}
// Just to verify that with Spans it could work, but not Span.ToArray()
public static void DoSpan(Span<Point> points)
{
for (int i = 0; i < points.Length; i++)
{
points[i].X++;
}
}
public static void Main()
{
Point[] points = new Point[4];
DoArray(points);
PrintArray("Complete Array", points);
DoArray(points[2..4]);
PrintArray("Array-Slice", points);
DoSpan(points.AsSpan(2..4));
PrintArray("Span", points);
DoArray(points.AsSpan(2..4).ToArray());
PrintArray("Span.ToArray()", points);
}
private static void PrintArray(string msg, IEnumerable<Point> points)
{
Console.WriteLine(msg);
foreach (var p in points)
{
Console.WriteLine($"\t{p}");
}
}
Now if I was programming in C, I could just pass the pointer the third element and the function wouldn't know that it is an array slice (of course I'd also need to pass a length/count). So I'm wondering whether C# does have something similar.

Related

Returning an Array Manipulates Original Value in C#

This is my first question on the site and I am sure I'll find my answer here.
For school, I was trying to do some basic C# coding for a challenge that was given to us.
Here is the problem:
Normally when I pass a value through a method I don't run into issues. Like so:
static void Main(string[] args)
{
// Declare Integer
int originalInt = 20;
// Call the Method
int multipliedInt = Multiplication(originalInt);
// Prompt
Console.WriteLine("Original: {0} Modified: {1}", originalInt, multipliedInt);
}
// Method
static public int Multiplication(int original)
{
// Quik Maffs
int modifiedValue = original * 2;
return modifiedValue;
}
The above example works just fine. The original value is 20 and the modified value is 40.
However, this changes when I attempt to do that with an array:
static void Main(string[] args)
{
// Declare Original Array
int[] originalArray = new int[] {1, 4, 6, 8, 12};
// Call Method
int[] multipliedArray = Multiplication(originalArray);
// Prompt
Console.WriteLine("Original: [{0}], Multiplied: [{1}]", String.Join(", ", originalArray), String.Join(", ", multipliedArray));
}
// Method
static public int[] Multiplication(int[] original)
{
// New Int
int[] modified = original;
// Loop
for (int i = 0; i < modified.Length; i++)
{
modified[i] *= 2;
}
return modified;
}
The code above returned the modified value twice. It seems like it modifies the original value as well.
Any idea why this is happening?
int is a value type. When you pass a value type to a method, you pass a copy of the value.
Arrays are reference types. When you pass a reference type to a method, you pass a copy of the reference... but both the copy and original still refer to the same object.
Now it seems you may have understood this much, because of this code:
(This is why I re-opened the question... the stock ref-vs-value answer wasn't gonna cut it here)
int[] modified = original;
However, the other thing that happens with reference types is assignments also only copy the reference. So modified and original in that snippet again refer to the same array object.
To fix this, you need to make an actual deep copy of the array. There are several ways to do this. I would tend to write the method this way:
static public IEnumerable<int> Multiplication(IEnumerable<int> original)
{
return original.Select(i => i * 2);
}
...and append a .ToArray() at the end of the method call if and only if I really need a full array (hint: very often it turns out you don't), like this:
int[] multipliedArray = Multiplication(originalArray).ToArray();
or like this:
var multipliedArray = Multiplication(originalArray);
But I understand there are a number of things here that aren't very familiar to a beginner. You might try something more like this:
static public int[] Multiplication(int[] original)
{
int[] modifed = new int[original.Length];
for (int i = 0; i < original.Length; i++)
{
modified[i] = original[i] * 2;
}
return modified;
}

How to manipulate structure (array inside)?

This is the structure:
public struct ProfilePoint
{
public double x;
public double z;
byte intensity;
}
It is used inside a callback function (I deleted most of it so it won't make sense, there is a for loop that cycle through every points (arrayIndex) that were scanned on a surface and process them. The result is stored inside profileBuffer):
public static void onData(KObject data)
{
if (points[arrayIndex].x != -32768)
{
profileBuffer[arrayIndex].x = 34334;
profileBuffer[arrayIndex].z = 34343;
validPointCount++;
}
else
{
profileBuffer[arrayIndex].x = 32768;
profileBuffer[arrayIndex].z = 32768;
}
}
}
I would like to process the data inside profileBuffer (both array, x & z).
So far I was "able" to create a function that get one value from profileBuffer with no error from visual studio:
public static int ProcessProfile(double dataProfile)
{
int test=1;
return test;
}
Putting this line:
ProcessProfile(profileBuffer[1].x);
Into onData() result in no error but that's just one value. Ideally, I would like to have the whole array. What confuse me is that every value stored inside profileBuffer are double (forget intensity). But stored in array. Yet I can't import the data like ProcessProfile(profileBuffer.x); I have to specify an index... Is it possible to manipulate a vector (line) of data? That would be ideal for me.
Sorry for the poor explanation / long post... I am quite newb.
you need
public static int ProcessProfile(ProfilePoint []points)
{
var x = points[4].x;
.....
}
and do
ProcessProfile(profileBuffer);

Having two param lists with same size

The method PrintTimes(string a, int b) prints the string a, b times (i.e. PrintTimes("test",3) will print testtesttest).
I want to create a method, which will get a params array of strings and a params array of integers. So the call function will ook like this
PrintTimes("A","B","C","D",2,1,3,2);
Or
PrintTimes("A",2,"B",1,"C",3,"D",2)
Both of which will print AABCCCDD
Since there can be only one params parameter in a method, this is impossible. So is there a way to do this?
I know I can create a Class with a string and an int variable, and create a params array for the class. But I'd rather not, since it would involve constructing a new Class for each set
Why not using a class
public class PrintParameter
{
public int Count {get;set;}
public string Content{get;set;}
}
Then
public void PrintTimes(List<PrintParameter> inputs)
{
//for each input print the "Content", "Count" times
}
Or
public void PrintTimes(params PrintParameter[] inputs)
{
//for each input print the "Content", "Count" times
}
If you don't want to define a class you may try something like List<KeyValuePair<string,int>> or other alternatives such as List<Tuple<string,int>> and etc. However the preferred way of doing is to use a class with meaningful properties.
How about just dropping the params keyword and taking arrays instead? That is, make the signature PrintTimes(string[], int[]). PrintTimes(new[]{"A","B","C","D"}, new[]{2,1,3,2}); isn't that much more to write.
There are several ways you can go about solving this problem. While you can only have one params, you can just make both your parameters arrays:
PrintTimes(string[] strings, int[] printCounts)
{
// Assert strings.Length == printCounts.Length
for (int i = 0; i < strings.Length; i++)
{
for (int j = 0; j < printCounts[i]; j++)
{
// Print strings[i]
}
}
}
Then it can be called like this:
int[] numbers = new int[3] {1, 2, 3};
string[] names = new string[3] {"Matt", "Joanne", "Robert"};
PrintTimes(names, numbers);
Following up on Hossein's suggestion, why not something as simple as:
void PrintTimes(List<String> strings, List<Int> count)
(or do it as an array as the comments said) Then inside PrintTimes require the inputs to be the same length or some logical fail when they don't.

Passing the dimension of an Array as a Parameter in C#

I'm learning C# and am trying to implement a versatile RandomVar class along with some methods for computing common statistics as practice. I'd like to be able form the arbitrary Joint probability RandomVariable from its components by instantiating a new variable of dimension N where N is passed into the constructor. I'd like to implement random Var X as two one dimensional lists of doubles, and the randomVar XY not as two lists of length n^2, but as a randomVar of type double[][] which otherwise can still use all of the same methods (ExpectedValue, Covariance, etc).
I'm having a lot of trouble implementing this. Other than the first naive approach (which had lots of copy and pasting), I've tried inheriting from a base RandomVar class into a JointRandomVar class -- still a lot of copy-pasting. Now I'm trying to the probabilities and outcomes arrays of Class RandomVar as Generics of type List -- this however produces a lot of problems as I can't figure out how to write the methods in an adaptable way (The std_Dev method can't iterate over the way it needs to in general -- so I need some flexible way to define the method so that if the "dimension" of the random Var is 2, the std_Dev method will do a double loop, or flatten out the array for the process of iterating).
Wanting some design help from more experienced programmers -- is having the probabilities/outcomes arrays List the best way to pass a parameter like this?
Thank you very much for your assistance.
EDIT: Here is the the version of the code for all doubles, so people can read it since the un-updated version seemed more confusing to people. I'd like to be able to have all of these methods work on objects of type double[] for any dimension of array, and it to be possible to instantiate the class with _values and _probs having any dimension.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Chapter_3_GUI
{
class RandomVar
{
private double[] _values;
private double[] _probs;
private double _mean;
private double _stddev;
private int _length;
private double _evalue;
public RandomVar(double[] values, double[] probs)
{
_values = values;
_probs = probs;
_mean = meanCalc(_values);
_stddev = stddevCalc(_values, _mean);
_length = _values.Length;
_evalue = expectedVal(_probs, _values, _length);
}
public double[] Values
{
get { return _values; }
set { _values = value; }
}
public double Mean
{
get { return _mean; }
}
public double Stdev
{
get { return _stddev; }
}
public static double meanCalc(double[] var)
{
double mean = var.Sum();
return mean;
}
public static double stddevCalc(double[] var, double mean)
{
double[] varianceArr = new double[var.Length];
for (int i = 0; i <= var.Length; i++)
varianceArr[i] = (var[i] - mean) * (var[i] - mean);
double variance = varianceArr.Sum();
double stddev = Math.Sqrt(variance);
return stddev;
{
}
}
public static double[][] multiplyProbs(RandomVar X, RandomVar Y, double[][] cprobMatrix)
{
double[][] probArr = new double[X._length][Y._length];
for (int i=0; i <= probArr.Length; i++)
{
for (int j =0; j <= probArr.Length; j++)
{
probArr[i][j] = Y._probs[j] * cprobMatrix[i][j];
}
}
return probArr;
}
public static RandomVar multiplyVars(RandomVar X, RandomVar Y, Func<double,double> f)
{
double[][] productArr = new double[X._length][Y._length];
for (int i=0; i<= productArr.Length; i++)
{
for (int j=0; j <= productArr.Length; i=j++)
{
productArr[i][j] = f(X._values[i], Y._values[j]);
}
}
double[][] probArr = multiplyProbs(X, Y, cprobMatrix);
RandomVar product = new RandomVar(productArr, probArr);
return product;
}
public static double expectedVal(double[] _probs, double[] _values, int _length)
{
double[] expectedArr = new double[_length];
for (int i = 0; i <= expectedArr.Length; i++)
{
expectedArr[i] = _probs[i] * _values[i];
}
double evalue = expectedArr.Sum();
return evalue;
}
public static double covarianceCalc(RandomVar X, RandomVar Y, Func<double, double> f)
{
RandomVar VarXY = multiplyVars(X, Y, f);
double correlation = expectedVal(VarXY._probs, VarXY._values, VarXY._length);
double covariance = correlation - (X._mean * Y._mean);
return covariance;
}
}
}
Is the cardinality of each dimension going to be the same? Your comment about "treating it as one long array of size n^k" suggests it is. That is, n is the length of value/probability pairs in each dimension.
The other question I have is, what is the reasoning behind passing the values and probabilities in two different arrays? If it were me, I'd declare a struct that contains the pairs, e.g.:
struct ValueProbPair
{
public readonly double Value;
public readonly double Probability;
public ValueProbPair(double value, double probability)
{
Value = value;
Probability = probability;
}
}
Finally, as far as your specific question goes…well, it's not clear what the specific question is. You seem to have a broad question regarding a flexible way to implement this.
It seems to me that the biggest challenge here (i.e. the roadblock with the least intuitively obvious solution) is in the title of your question:
Passing the dimension of an Array as a Parameter
You can do this, i.e. create an appropriate array object, by using the Array.CreateInstance(Type, int[]) overload. IMHO, it will also work better if (but is not required that) you can consolidate the value/probability pairs into a single struct.
The other big caveat is that you won't get the benefit of compiler optimizations for accessing array elements. You'll have to use e.g. the GetValue() method, which will most likely prevent the compiler from accessing array elements directly (the optimization is theoretically possible, but seems unlikely to me).
So, for example, you could do something like:
Array Combine(ValueProbPair[] newDimension, Array previousDimensions)
{
int[] rankLengths = new int[previousDimensions.Rank + 1];
for (int j = 0; j < previousDimensions.Rank; j++)
{
rankLengths[j] = previousDimensions.GetLength(j);
}
rankLengths[previousDimensions.Rank] = newDimension.Length;
Array result = Array.CreateInstance(typeof(ValueProbPair), rankLengths);
// then fill in your matrix using GetValue and SetValue to
// access individual array elements...
// Finally, return the new multi-dimensional array:
return result;
}
The various array method overloads that access elements use params array parameters, so you can without too much difficulty write code that can handle matrices of arbitrary dimension. E.g.:
IEnumerable<double> GetAllValues(Array source)
{
int[] index = new int[source.Rank];
while (true)
{
yield return (double)source.GetValue(index);
int j = 0;
while (++index[j] == source.GetLength(j))
{
index[j] = 0;
if (++j == index.Length)
{
yield break;
}
}
}
}
One last note: for dealing with value/probability, depending on your scenario you might actually find it makes more sense to do all this using dictionaries. There are different complications, but the basic building block would be Dictionary<double, object>, where the value is either double or another Dictionary<double, object>. Then if you are looking for e.g. a combined probability, you don't have to scan lists of values, but rather can just look them up directly as the key in the dictionary.

Is it possible to use a method argument as an array extension method

I am trying to pass an argument to a method, and then use that argument as a array extension method, but I am struggling. My code is:
//create method
public static void BankChoice(string SearchItem)
{
//declare variables
double tempMin = 0;
int minIndex = 0;
//set a temporary double as the first index of array
tempMin = Program.array_SH1[0].SearchItem;
//start loop to go through whole array
for (int y = 0; y <= array_SH1.Length; y++)
{
//if the temp double is bigger than the array item,
//make array item temp double
if (tempMin > array_SH1[y].SearchItem)
{
tempMin = array_SH1[y].SearchItem;
minIndex = y;
}
}
}
I would then call the code as:
BankChoice("OpenPrice")
However this doesn't work. The compiler won't accept the string as the array extension and it just throws and error.
Is there anyway to fix this without having to do it longhand, and create a method for all variations of SearchItem
Thanks
What you can do is to supply a delegate:
public static void BankChoice(Func<ArrayValueType, double> searchBy)
{
//...
// use the delegate to evaluate the result for each time you need to get the value from an item in your array.
tempMin = searchBy(Program.array_SH1[0]);
//...
}
Where ArrayValueType is the type of object in your array. Then you call it with
BankChoice(x => x.OpenPrice);
This will allow you to specify a property to search on, and it will be done in a type safe manner. The only restriction at the moment is that the property is convertible to a double. It's possible to get around that for properties of a generic type, and there are various ways to do that depending on what your needs are.

Categories