0

I am reading samples from a serial port continously and I want to show the last 400 samples in a graph. So when the number of received samples becomes 400 I should shift the myPointFsList to left by 1 and add the last received sample to the end of it. My below code works successfully while the first 400 samples.

    List<PointF> myPointFs = new List<PointF>();
    uint sampleNumber = 0; PointF Current_PointFs;

    private void UpdateVar(object sender, EventArgs e){
        ...
       Current_PointFs = new PointF((float)(sampleNumber), (float)newSample);
       if (sampleNumber < 400)
          {
            myPointFs .Add(Current_PointFs);
            ++sampleNumber;
          }
       else
          {        
           myPointFs  = myPointFs .ShiftLeft(1); //ShiftLeft is an Extension Method
           myPointFs.Add(Current_PointFs);
          }
       if (myPointFs.Count >= 2)
          {
           Configure_Graphs();// using Graphics.DrawLines(thin_pen, myPointFs.ToArray()) to draw chart
          }
    }

But after that the first 400 samples recieved, I need to substract 1 from myPointFs[i].X to shift X-axis to left by 1. Maybe a way is to run a for loop. How can I implement it? Or is there any more elegant way? Or something that it exists out-of-the-box in C#?

Edit: (To make my question more clear)

myPointFs contains something like this:

myPointFs[0] = {X = 1, Y = 21}
myPointFs[1] = {X = 2, Y = 50}
myPointFs[2] = {X = 3, Y = 56}

now I will remove the first element by shifting left by 1 and add a new sample to the end.

myPointFs[0] = {X = 2, Y = 50}
myPointFs[1] = {X = 3, Y = 56}
myPointFs[2] = {X = 4, Y = 68}

But I need finally something like this:

myPointFs[0] = {X = 1, Y = 50}
myPointFs[1] = {X = 2, Y = 56}
myPointFs[2] = {X = 3, Y = 68}
IndustProg
  • 627
  • 1
  • 13
  • 33
  • I think you could use a linkedlist instead of list, and use removeFirst – Gonen I Feb 01 '18 at 08:56
  • 1
    If I understand correctly, you want to remove the first point in the list when you add another. A `Queue` will be perfectly suitable for that. – Dennis_E Feb 01 '18 at 08:59
  • I remove the first element successfully by `ShiftLeft` Extension methods. My question is about shifting X value of all new shifted elements by 1. – IndustProg Feb 01 '18 at 09:01
  • Its not clear what you mean by that. – Gonen I Feb 01 '18 at 09:03
  • I am Editing my question to make it more clear. – IndustProg Feb 01 '18 at 09:05
  • 1
    I think you might mean updating all values in a collection. If so, check this out: https://stackoverflow.com/questions/398871/update-all-objects-in-a-collection-using-linq – Gonen I Feb 01 '18 at 09:08

2 Answers2

3

So, you want to remove the first element and decrement the X value of each remaining point. You can do that in one go:

myPointFs = myPointFs.Skip(1).Select(p => new PointF(p.X-1, p.Y)).ToList();
Dennis_E
  • 8,751
  • 23
  • 29
  • Yes I want to remove the first element and add new received sample to end of the list , and then decrement X value of each remaining element. – IndustProg Feb 01 '18 at 09:27
  • Besides, you don't need an extension method to shift the elements in a list. `myPoints.RemoveAt(0)` will do that.Normally, that is inefficient. It takes 400 steps because the rest of the items will move back one spot. But since you need to loop over all the elements anyway this becomes moot in this case. – Dennis_E Feb 01 '18 at 09:31
  • Thanks, It is useful. I will change my code. Although pay attention that I used `List.GetRange` Method to shift left which creates a shallow copy not a deep copy. – IndustProg Feb 01 '18 at 09:40
  • Using `GetRange()` will have the same result. `GetRange()` will make a copy of the list. (Still an O(n) operation, aka 399 steps) – Dennis_E Feb 01 '18 at 09:45
  • From MSDN for `List.RemoveAt` Method: This method is an O(n) operation, where n is (Count - index). I am confused! – IndustProg Feb 01 '18 at 10:03
  • The same documentation says that `GetRange()` is also an O(n) operation. A shallow copy is still a **copy**. If you look at the source, you can see that both method amount to doing `Array.Copy()` http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,9a8ba04be8b690be,references – Dennis_E Feb 01 '18 at 10:07
1

That is job for Queue<T>. In your case X will be index and Y will be data inserted into Queue. Here's some code to show how that works:

    static void Main(string[] args)
    {
        var queue = new Queue<int>(10); //Capacity of Queue is 10

        Console.WriteLine("=== Writing to Queue ===");

        for (int i = 0; i < 23; ++i) //22 rounds for inserting data
        {
            DequeueIfFull(i, queue);

            Console.WriteLine("Inserting number {0} into Queue", i);
            queue.Enqueue(i); //Read and remove the first item in Queue
        }

        FlushQueue(queue); //Last time read all values from queue

        Console.ReadKey();
    }

    private static void DequeueIfFull(int i, Queue<int> queue)
    {
        var tenthItemInserted = (i != 0) && (i % 10 == 0);

        if (tenthItemInserted)
        {
            Console.WriteLine("Dequeuing from Queue");
            for (int j = 0; j < 10; ++j)
            {
                Console.WriteLine("  Number dequeued on position {0} is {1}", j, queue.Dequeue());
            }
        }
    }

    private static void FlushQueue(Queue<int> queue)
    {
        Console.WriteLine();
        Console.WriteLine("=== Reading final Queue state ===");
        var index = 0;

        foreach (var itemInQueue in queue)
        {
            Console.WriteLine("At position {0} is number {1} ", index, itemInQueue);
            index++;
        }
    }

Documentation for Queue and link to nice articles about Data Structures.

krs
  • 543
  • 2
  • 17