1. Welcome to TechPowerUp Forums, Guest! Please check out our forum guidelines for info related to our community.

c# subtract elements of a list

Discussion in 'Programming & Webmastering' started by ste2425, Aug 1, 2013.

  1. ste2425

    ste2425

    Joined:
    May 27, 2008
    Messages:
    3,462 (1.46/day)
    Thanks Received:
    392
    Location:
    Huddersfield, uk
    Hi all

    I have two lists of DateTime. One represents the start time of a task, the second the finish time. I need to subtract the contents of one from the other to end up with a list representing the duration of each task. Im aware that subtracting two DateTime's returns a TimeSpan and that is great for what I need.

    Im currently performing it within a series of loops as im still stuck im my programming ways for c# in microcontrollers doing DSP but now im using asp.net and wondering if theres any extra functionality of this framework that can perform the task in a more elegant and readable way.

    Theres no need to worry about aligning the data in the list as they are already aligned, so the first elements of each list match, second, third etc.

    Many thanks all

    Stephen
     
  2. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    13,956 (6.25/day)
    Thanks Received:
    3,795
    Location:
    IA, USA
    I would put the start and finish times in a custom class then add an instance of the class to a List<class>. That way you only have one list and that one list contains everything relevant. If you want to go a step further, I would add an accessor called Duration that returns Finish - Start. Put it all together, you could do something like list[9].Duration to get how long task 9 took. Ideally, this custom class would contain everything relevant to the job (even the job itself) so this all happens in isolated code.

    To remove elements from a list, use .Remove(index) or .Remove(copy of instance). If it is in a for loop, make sure to run the loop in reverse (i-1) otherwise it will freak out.

    If this isn't homework and the code is something that can be made public, I could take a look and/or optimize it for you so you can see a working example of what I'm talking about.
     
    Last edited: Aug 1, 2013
    ste2425 says thanks.
    Crunching for Team TPU
  3. BiggieShady

    BiggieShady

    Joined:
    Feb 8, 2012
    Messages:
    1,023 (1.00/day)
    Thanks Received:
    351
    Location:
    Zagreb, Croatia
    This.
    Create EventInfo class with DateTime EventStart, DateTime EventEnd, and a TimeSpan property Duration (with only getter) that gets EventEnd-EventStart.
    Then you keep the list of EventInfo instances.
     
    ste2425 says thanks.
  4. ste2425

    ste2425

    Joined:
    May 27, 2008
    Messages:
    3,462 (1.46/day)
    Thanks Received:
    392
    Location:
    Huddersfield, uk
    Thanks I will look into your methods.

    Nope this isn't homework but it is for work. recently got my first job as a web developer and its technology I've never worked with before (any .net technology) so its a little tough to adapt my current programming techniques around this new, to me, framework. So in a nut shell I wan't to do it off my own back and even if I wanted to give you code I couldn't but the offer is appreciated. plus you've given me the idea of how to do it which should enough to work the rest out myself so thanks all.
     
  5. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    13,956 (6.25/day)
    Thanks Received:
    3,795
    Location:
    IA, USA
    What I suggested is basically making the code object-oriented instead of procedural. I'll give a basic example using pseudo-variables:
    Code:
    using System;
    
    public class Task
    {
      private DateTime _Start = new DateTime();
      public DateTime Start
      {
        get { return _Start; }
        set { _Start = value; }
      }
    
      private DateTime _Stop = new DateTime();
      public DateTime Stop
      {
        get { return _Stop; }
        set { _Stop = value; }
      }
    
      public TimeSpan Duration
      {
        get { return _Stop - _Start; }
      }
    
      public Task() { }
      public Task(DateTime start, DateTime stop)
      {
        _Start = start;
        _Stop = stop;
      }
    }
    I didn't compile the above code but it should work.

    Duration could be made into a function but I decided to make it a read-only property because you may have never seen one of those before. They're useful for menial tasks like a quick subtraction.

    Additionally, I don't know if you're using strongly-typed lists but I'd recommend using them. It eliminates all the silly type-casting. They are in System.Collections.Generic and called like List<Task>.

    Which reminds me of something else: you can add a custom indexor to any class by overriding the "this" property:
    Code:
            public VdfKey this[string name]
            {
                get
                {
                    for (int i = 0; i < _Keys.Count; i++)
                    {
                        if (_Keys[i].Name.ToLower() == name.ToLower())
                            return _Keys[i];
                    }
                    return null;
                }
                set
                {
                    for (int i = 0; i < _Keys.Count; i++)
                    {
                        if (_Keys[i].Name == name)
                            _Keys[i] = value;
                    }
                }
            }
            public VdfKey this[int child]
            {
                get { return _Keys[child]; }
                set { _Keys[child] = value; }
            }
    In the above example, you could get a VdfKey out of a collection using index or by name. It simplifies code like this:
    Code:
     key.Child[name].Child[3].Child[name2].Child[5]
    To this:
    Code:
    key[name][3][name2][5]
    Far less to type and more readable to boot. It's really awesome because you can turn literally any class instance into an array using it. For example, plug this into the code above:
    Code:
    public object this[int property]
    {
      get
      {
        switch (property)
        {
           case 0: return _Start;
           case 1: return _Stop;
           case 2: return Duration;
        }
      }
      set
      {
        switch (property)
        {
           case 0: _Start = (DateTime)value;
           case 1: _Stop = (DateTime)value;
           // Duration is not writable and is calculated on the fly so there is nothing to set for it.
        }
      }
    }
    And you could access Duration by simply doing Task[2]. Of course, it isn't as fast as .Duration but still neat none-the-less.
     
    Last edited: Aug 1, 2013
    ste2425 says thanks.
    Crunching for Team TPU
  6. ste2425

    ste2425

    Joined:
    May 27, 2008
    Messages:
    3,462 (1.46/day)
    Thanks Received:
    392
    Location:
    Huddersfield, uk
    That is fantastic thanks for such a comprehensive write up. That's why I'm such a huge fan of TPU everyone goes out of their way to give that bit extra help.

    That'l make it much easier to understand what im doing and allow me to run through your examples thanks again :)
     
  7. FordGT90Concept

    FordGT90Concept "I go fast!1!11!1!"

    Joined:
    Oct 13, 2008
    Messages:
    13,956 (6.25/day)
    Thanks Received:
    3,795
    Location:
    IA, USA
    Oh, and another thing. If Duration is going to be accessed a lot but its value changed infrequently, you can make the setter properties on Start and Stop update a _Duration variable that is simply read:
    Code:
    using System;
    
    public class Task
    {
      private DateTime _Start = new DateTime();
      public DateTime Start
      {
        get { return _Start; }
        set
        {
          _Start = value;
          if ((_Stop != default(DateTime)) && (_Stop > _Start))
            _Duration = _Stop - _Start;
        }
      }
    
      private DateTime _Stop = new DateTime();
      public DateTime Stop
      {
        get { return _Stop; }
        set
        {
          _Stop = value;
          if ((_Start != default(DateTime)) && (_Stop > _Start))
            _Duration = _Stop - _Start;
        }
      }
    
      private TimeSpan _Duration = new TimeSpan();
      public TimeSpan Duration
      {
        get { return _Duration; }
      }
    
      public Task() { }
      public Task(DateTime start, DateTime stop)
      {
        _Start = start;
        Stop = stop; // modify this to use the setter in order to update _Duration.
      }
    }
    If you did .Start = DateTime.Now, .Duration would remain default(TimeSpan); if you did .Stop = DateTime.Now after that, .Duration would contain the difference between the two. It ignores changes unless both are not default making it easy to check Duration for whether or not it ran at all.

    Edit: There is a chance that Start may be submitted after Stop in a case where Start and Stop are already set. It would result in a negative value in Duration which is improper. If such is the case, I added a comparison to both setters to make sure Duration will never be negative.
     
    Last edited: Aug 1, 2013
    Crunching for Team TPU

Currently Active Users Viewing This Thread: 1 (0 members and 1 guest)

Share This Page