0

I have a Point struct:

public struct Point
{
    public Point(double x, double y, double z)
    {
        X = x;
        Y = y;
        Z = z;
    }

    public double X;
    public double Y;
    public double Z;
}

then in the following code, I am creating an array of points and then dividing each points by a value 2

//Create a test array of Points
Point[] testPointArray = new Point[2];
testPointArray[0] = new Point(2, 4, 8);
testPointArray[1] = new Point(6, 12, 24);

//Divide by 2
testPointArray = testPointArray.Select(point => point = new Point(point.X / 2, point.Y / 2, point.Z / 2)).ToArray();

Question: In the above code, I am using the new operator to replace each point with a newly created point. How can I directly make changes in the existing point (i.e. avoid creating new points)? I tried to do the following code, but the syntax is wrong:

testPointArray = testPointArray.Select(point =>
{
    point.X = point.X / 2;
    point.Y = point.Y / 2;
    point.Z = point.Z / 2;
}).ToArray();
5
  • 2
    You should create new instances, structs are value types and they should be immutable. Commented May 20, 2022 at 10:01
  • if you used class instead of struct and its inside a list you can try ForEach, see example. Commented May 20, 2022 at 10:03
  • @jalsh interesting point, why? Commented May 20, 2022 at 10:06
  • 1
    value types are copied when passed as arguments, hence any modification happening on them will happen within the scope of that function. This can cause a lot of confusion\errors. Thus it's recommended that you keep your structs immutable. See this answer Commented May 20, 2022 at 10:08
  • IMO (bring pitchforks and torches!) LINQ was meant as a functional extension (see this and this). I would use a plain old for loop or, given you have 2 points, just inline the calls and skip looping altogether. Commented May 20, 2022 at 10:18

1 Answer 1

3
testPointArray = testPointArray.Select(point =>
{
    point.X /= 2;
    point.Y /= 2;
    point.Z /= 2;
    return point;
}).ToArray();

In your example your lambda returns nothing - adding return point returns the mutated point for your select.

I agree with jalsh's comment that you should create new points, something like:

testPointArray = testPointArray.Select(point => new Point(point.X / 2, point.Y / 2, point.Z / 2))
            .ToArray();
Sign up to request clarification or add additional context in comments.

6 Comments

good answer, fyi for OP, this is still creating new points, you're just not initializing it yourself
In both cases, you are still creating a new point. As, Jalsh mentioned, the Structs are immutable so, I should either use class to avoid creating new points OR else I must create a new point.
One way to see this happening is by running ForEach instead of Select try: Array.ForEach(testPointArray, point =>{point.X = point.X / 2; point.Y = point.Y / 2; point.Z = point.Z / 2;}); this will return the same (old) values although you have modified your fields
@jalsh will that work if you're not pasing point as ref point? Doesn't seem to: ideone.com/FCSuPT
@orhtej2 yes, it won't... that was my point (pun not intended). this shows that the function is operating on a COPY of Point
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.