0

I've figured out how to store Data from a .csv to a List<>.

I've two Lists: ListA which contains the timestamp for each value and ListB which contains the values.

It looks like this:

A (time [ms])  | B (value)
---------------------------
0,00           | 49,33
154,71         | 49,46
244,92         | 49,72
855,11         | 49,64

...
And so on (over 50.000 values)

My actual issue is: I want to send the values to the console using WriteLine(listA[i]); at the (nearly) exact time like the timestamp of the actual value.

I thought about a stopwatch which i compare with the timestamps to give the right value out at the right moment?

Is this possible?


Update #1:

Here is my code. It works (kind of). But i'm not sure if there is a much better solution?

stopwatch.Start();

while(true)
{ 
    for (int i = 0; i < 50000; i++)
    {
        if (Math.Abs(stopwatch.Elapsed.TotalMilliseconds - Convert.ToDouble(listA[i]) * 1000) < 10)
        {
            Console.WriteLine(listB[i]);
        }
    }
    Thread.Sleep(5);
}

Update #2:

I'm trying to understand the solution of Mong Zhu @disclaimer. My target is to create a method which get initiated by a timer (every 100ms as example). I already have the code around this Problem is: Timestamp and Stopwatch are sometimes not synced and it skips some values.

Here is my method (called every 100ms):

public double getvalue()
    {

        if (stopwatch.ElapsedMilliseconds > Convert.ToDouble(ListA[ListA.Count-1])*1000)
        {
            stopwatch.Stop();
        }
        else
        {
            for (var i = 0; i < ListA.Count; i++)
            {
                if (Math.Abs(stopwatch.ElapsedMilliseconds - Convert.ToDouble(ListA[i]) * 1000) < 5)
                {
                    value = Convert.ToDouble(ListB[i]);
                    break;
                }
            }
        }

        return value;
    }
William
  • 15
  • 1
  • 7
  • What's the dimension of the timestamp? Are those seconds or milliseconds or nanoseconds? If it's not too small, a timer may be _nearly_ exact (for a given value of "nearly"). – René Vogt Jan 22 '18 at 14:38
  • short answer: YES. Although a resolution of `855,11` milliseconds might be hard to achieve. But unfortunately this is not a code writing service. Please provide the code that you have written which at least tries to solve the problem. Describe where exactly you got stuck and we can help you. Up to now the question is too broad and might be closed for that reason. – Mong Zhu Jan 22 '18 at 14:39
  • @RenéVogt the dimension is milliseconds. What do you mean with "this is not a code writing service"? – William Jan 23 '18 at 06:26
  • What I meant was that in your first post you simply presented a problem to be solved without any code that shows an attempt to solve it by yourself. Now the post looks different, and we can start addressing the problems in your solution. I would change the order or `for` and `while` loop. You can also use a `Timer`. Give me a minute, then I write an answer – Mong Zhu Jan 23 '18 at 07:21
  • Correction: The dimension is seconds. – William Jan 23 '18 at 07:52
  • I also changed it in your post `List A (time in sec) ` – Mong Zhu Jan 23 '18 at 08:11

2 Answers2

0

Your implementation would be much easier if instead of having two separate lists you have only one list of the type you need. Let me explain:

You create a class with the properties you need:

public class YourClass
{
     public long TimeMS {get; set;}
     public Double Value {get; set;}
}

Then you can simply create a List<YourClass>

List<YourClass> list = new List<YourClass>();

list.Add( new YourClass { TimeMS = 154.71, Value = 49.46 } );

Then it would be much easier to iterate:

foreach(YourClass c in list)
{
     //DO ALL YOUR WORK
     Console.WriteLine(c.TimeMS.ToString() + ": " + c.Value.ToString());
}
NicoRiff
  • 4,803
  • 3
  • 25
  • 54
  • nice solution, but I guess you missed the point: "I want to send the values to the console (.WriteLine(listA[i]);) at the (nearly) exact time like the timestamp of the actual value." the timestamp is supposed to tell you **when** you write the value – Mong Zhu Jan 22 '18 at 15:18
0

If you want to use a StopWatch then I would switch the for and the while loop. Only iterate to the next position after you have overstepped the time interval and wrote the value to the console. Here is an examplary program:

void Main()
{
    Stopwatch stopWatch = new Stopwatch();
    List<int> ListA = new List<int>() { 0, 154, 244, 855 };
    List<double> ListB = new List<double>() { 49.33, 49.46, 49.72, 49.64 };

    stopWatch.Start();

    for (int i = 0; i < ListA.Count; i++)
    {
        while (stopWatch.ElapsedMilliseconds < ListA[i] * 1000) 
        {
            Thread.Sleep(5); 
         }

        Console.WriteLine($"Value: {ListB[i]} TIME: {stopWatch.ElapsedMilliseconds}");
    }

    stopWatch.Stop();

    Console.ReadKey();
}

Problems in your code:

1) for (int i = 0; i < 50000; i++)
Preferably dont' use a fixed number for the for loop if you iterate over a collection. The collection might change in size and the fixed number will lead either to an out of bounds exception or to not handled values. Use Count if it is a List or Length if it is an array

2) In each while-iteration you are iterating over the entire array. This is a strong overhead, if you actually want to print value by value.

Disclaimer. The while loop in my solution is called buisy-waiting. This is not really adviseable since the CPU is occupied while doing actually nothing. A preferable solution would be to use a timer:

System.Timers.Timer timer = new System.Timers.Timer();
// register the event which will be fired
timer.Elapsed += PrintValuesAtTime;
timer.Interval = 1; // an intervall of 0 is not allowed
timer.AutoReset = true; // repeated execution of the timer
timer.Start(); // start the timer

Console.ReadLine();

I would make a new list which contains all timestamp differences from ListA which can be used as an intervall for the next printing. Something like:

List<int> ListAIntervals = new List<int>() { 0, 154-0, 244-154, 855-244 };

and in the Elapsed event handler you can handle the printing logic. You would need an external counter to iterate over you collection:

private void PrintValuesAtTime(object sender, EventArgs args)
{
    System.Timers.Timer timer = sender as System.Timers.Timer;
    // only print values if there are enough values
    if (counter < ListAIntervals.Count && counter < ListB.Count)
    {
        Console.WriteLine($"Value: {ListB[counter]}");
        // there needs to be enough intervals left to go one more time
        if (counter < ListAIntervals.Count - 1 && counter < ListB.Count - 1) 
        {
            counter++;
            timer.Interval = ListAIntervals[counter] * 1000; // to make it in msec
        }
        else
        {
            // stop the timer
            timer.AutoReset = false;
        }
    }       
}
Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
  • 1) Yes, you are right. I'm still learning C# :). 2) Yeah. I thought about it, but at this moment i was happy that it works. Your solution produces less overhead. 3) The factor 1000 was a copy/paste mistake. The values in the List are seconds but with three decimals. – William Jan 23 '18 at 07:41
  • Can i still use e.g. Thread.Sleep(5) ? The cpu load without it is around 25%. – William Jan 23 '18 at 07:47
  • if the values are in seconds then you should delete your comment "the dimension is milliseconds. " – Mong Zhu Jan 23 '18 at 07:50
  • of course you can use the sleep function, I thought you would miss the time values if you would use it, but since the values are in seconds, looks fine to me. – Mong Zhu Jan 23 '18 at 07:54
  • okay thank you. I try to understand your solution @disclaimer. My target is to create a method which get initiated by a timer (every 100ms as example). I already have the code around this. I will post my actual solution (the method) which i'm using at the moment. Problem is: Timestamp and Stopwatch are sometimes not synced and it skips some values. – William Jan 23 '18 at 16:11
  • why do you try to call the method every 100 msec? If you want to go with a stopwatch then you need to do the buisy waiting thing in a while loop. This way it gets iterated almost every milli second. Otherwise use a `Timer` and set the intervall precisely to the time that you need calculated from your list as I have shown it in the second example. `StopWatch` is not a timer! it's a stopwatch ;) – Mong Zhu Jan 23 '18 at 17:43
  • I call it when i need my value. 100msec is only an example. Okay i will try it with a timer instead of stopwatch. – William Jan 24 '18 at 06:38