Masoud Andalibi
Masoud Andalibi

Reputation: 3228

How to remove a range from a list within a loop?

Greetings Please keep in mind there is no database and these are fake functions to make the component work for testing, i have a List which makes a 24 hours based on 15 minutes scale and produces from this method:

    public List<ScaleLine> GetHoursAndScales(ScaleLine.Scales scale = ScaleLine.Scales.Fiftheen)
    {
        int _scale = Convert.ToInt32(scale);
        int _count = _scale * 24;
        int _scaleCount = 60 / _scale;

        List<ScaleLine> _list = new List<ScaleLine>();

        var start = DateTime.Today;
        var clockQuery = from offset in Enumerable.Range(1, _count)
                         select TimeSpan.FromMinutes(_scaleCount * offset);
        foreach (var time in clockQuery)
        {
            _list.Add(new ScaleLine() { Id = _list.Count, Hours = (start + time).ToString("HH:mm"), Scale = _scale });
        }
        return _list;
    }

And i have another list which is called Reserved hours which is produces on this method:

    public List<Reservedhours> AllReservedHours()
    {
        return new List<Reservedhours>
        {
            new Reservedhours() { Id = 1, Date = DateTime.Now, StartPoint = "08:00", EndPoint = "10:00" },
            new Reservedhours() { Id = 2, Date = DateTime.Now, StartPoint = "14:00", EndPoint = "16:00" },
            new Reservedhours() { Id = 3, Date = DateTime.Now, StartPoint = "20:00", EndPoint = "22:00" },
            new Reservedhours() { Id = 4, Date = DateTime.Now.AddDays(1), StartPoint = "07:00", EndPoint = "11:00" },
            new Reservedhours() { Id = 5, Date = DateTime.Now.AddDays(1), StartPoint = "13:00", EndPoint = "15:00" },
            new Reservedhours() { Id = 6, Date = DateTime.Now.AddDays(1), StartPoint = "15:00", EndPoint = "18:00" },
            new Reservedhours() { Id = 7, Date = DateTime.Now.AddDays(1), StartPoint = "18:00", EndPoint = "22:00" },

        }; 
    }

Now i have another list that produces the available hours based on reserved hours and first list that produces 24 hours:

    public List<ScaleLine> GetAvailableHours(DateTime date, ScaleLine.Scales scale = ScaleLine.Scales.Fiftheen)
    {
        List<Reservedhours> _timeLine = AllReservedHours().Where(x => x.Date.Date == date.Date)
            .Select( a => new Reservedhours {StartPoint = a.StartPoint, EndPoint = a.EndPoint } )
            .ToList();
        List<ScaleLine> _available = GetHoursAndScales();

        //scale convert:
        int _scale = Convert.ToInt32(scale);

        foreach (var _item in _timeLine)
        {
            int index = _available.Where(x => x.Hours == _item.StartPoint)
                .SingleOrDefault().Id;

            //Convert to datetime
            DateTime _opening = DateTime.ParseExact(_item.StartPoint, "HH:mm", System.Globalization.CultureInfo.InvariantCulture);
            DateTime _closing = DateTime.ParseExact(_item.EndPoint, "HH:mm", System.Globalization.CultureInfo.InvariantCulture);
            //Getting duration time
            TimeSpan duration = _closing.Subtract(_opening);
            double _duration = duration.TotalMinutes;
            //getting coverage
            int timeScale = 60 / _scale;
            int coverage = Convert.ToInt32(_duration) / timeScale;

            //remove unavailable timespots
            _available.RemoveRange(index, coverage);
        }
        return _available; 
    }

But problem is when the Foreach loop starts it removes the first range correctly based on its index, lets say if _available list has 96 members it removes 8 of them, so second time it should have 88 members and find the index within those 88 members but it doesn't and gets the index wrong (it takes the index as if the list still had 96 members) and so goes for every other action within the loop. how can i fix this issue? is there a way i can get the available list without doing a foreach loop?

Upvotes: 1

Views: 90

Answers (1)

Oliver
Oliver

Reputation: 45101

The problem is your determination of the index. Instead of asking the list for the index of the desired object, you ask for the property value of an object and using this as index:

int index = _available.Where(x => x.Hours == _item.StartPoint)
                      .SingleOrDefault()
                      .Id;

Either you ask really for the index by calling IndexOf():

var matchingItem = _available.Where(x => x.Hours == _item.StartPoint)
                             .First();
var index = _available.IndexOf(matchingItem);

Or you replace your .RemoveRange() by something else, that really removes your desired elements.

Upvotes: 1

Related Questions