Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a struct component a variable?

Tags:

c#

list

Not sure I am asking this right or this even possible. I feel to explain my question it is best to ask right in the code at the relevant places so please see my comments in the snippet below.

I wonder how to achieve this without building a new list of values for each I iteration. I feel this should not be necessary.

The bigger picture of this loop is to plot individual dimensions of 3D points to three new 2D plots of these. Hope that makes sense.

for (int i = 0; i < 3; i++) // 3 iterations (X,Y;Z)
{           
    // what here? how to make the data component of Vector3D a variable
    for (int k = 0; k <= Points.Count - 1; k++)
    {
        Vector2D TL = new Vector2D();

        TL.x = ((1 / (float)FrameCount.Sum()) * k);
        TL.y = Points[k].x;      // on i = 0 want Points[k].x
                                 // on i = 1 want Points[k].y
                                 // on i = 2 want Points[k].z

        TimelinePoints.Add(TL); // just collect to a flat list for now
    }
}
like image 628
nuis Avatar asked Feb 18 '18 15:02

nuis


2 Answers

One option would be to have an array of extraction functions that you could apply to points. You can then use the LINQ Select overload that accepts a Func<TInput, int, TOutput> to generate a sequence of the values you want to add, and add it to TimeLinePoints that way.

// Possibly store this in a static variable somewhere
var extractors = new Func<Point, float>[] { p => p.x, p => p.y, p => p.z };

// Just do this once; store the result as a float for simplicity when dividing later.
float frameSum = FrameCount.Sum();
foreach (var extractor in extractors)
{
    TimeLinePoints.AddRange(Points.Select((point, index) =>
        new Vector2D(index / frameSum, extractor(point));
}

(You could go even further using SelectMany potentially, but that's where I'd start...)

like image 196
Jon Skeet Avatar answered Oct 12 '22 22:10

Jon Skeet


A considerably more pedestrian approach compared to Jon Skeet's answer would be to modify the Point struct to include an indexer, assuming that is an option:

public struct Point
{
  float x;
  float y;
  float z;

  public float this[int index]
  {
    get
    {
      switch (index)
      {
        case 0:
        return x;
        case 1:
        return y;
        case 2:
        return z;
        default:
        throw new IndexOutOfRangeException();
      }
    }
    set
    {
      switch (index)
      {
        case 0:
        x = value;
        break;
        case 1:
        y = value;
        break;
        case 2:
        z = value;
        break;
        default:
        throw new IndexOutOfRangeException();
      }
    }
  }
}

Then you could assign the proper field according to the value of your loop counter, like so:

for (int k = 0; k < Points.Count; k++)
{
    Vector2D TL = new Vector2D();

    TL.x = ((1 / (float)FrameCount.Sum()) * k);
    TL.y = Points[k][i];

    TimelinePoints.Add(TL); // just collect to a flat list for now
}
like image 34
Mark Benningfield Avatar answered Oct 13 '22 00:10

Mark Benningfield