marcuthh
marcuthh

Reputation: 596

C# - Recursively access subsection of List<>

I'm working on a program that operates as a Car Park simulator. To do this, I have:

A class called ParkingSpace

A List<ParkingSpace>

A class called Level (contains List<ParkingSpace> as an attribute)

A List<Level>

The number of spaces in the List<ParkingSpace> list is decided via user input. Once all of the ParkingSpace instances have been added to the list, I would like to spread them evenly across the number of levels (i.e. if there are 30 spaces and 3 levels, 10 spaces are added to the List<ParkingSpace> attribute of each Level instance.

With this example in mind, I have tried to get the first 10 spaces into the first level, the middle 10 spaces into the second level, and the last 10 spaces into the third level. I have tried to carry this out using a for loop, and the List<ParkingSpace>.getRange() method, as shown below:

//number of spaces to be set on each level
//total spaces divided by levels to be spread across
int spacesPerLevel = spaces.Count / numLevels;

//for as many levels as there are
for (int i = 0; i < numLevels; i++)
{
    //level at index holds range
    //level index multiplied by number of spaces on any one level
    int listRangeStart = (i * spacesPerLevel);

    //create sub-collection of spaces to be applied to level
    ParkingSpaces subSpaces = spaces.getRange(listRangeStart, spacesPerLevel);

    //add these spaces to level
    Level level = new Level(subSpaces);
    //add created level to collection of levels
    Add(level);

    //remove these spaces from ParkingSpaces collection once applied to level
    //try to prevent loose collection of spaces not applied to levels
    spaces.RemoveRange(listRangeStart, spacesPerLevel);
}

I'd have thought this would have worked fine, but for some reason I continue to get an OutOfRangeException on the getRange() method.

I've done the maths on the algorithm and it should work as far as I know. Can anyone spot any problems here that might be throwing it off? Alternatively, is there a simpler way to go about adding a subset of the main list another list recursively?

Upvotes: 0

Views: 208

Answers (4)

Stephen Byrne
Stephen Byrne

Reputation: 7505

Alternatively, is there a simpler way to go about adding a subset of the main list another list recursively?

Well there isn't really any recursion involved in your code anyway, but here is a simple way to so it:

for(int i=0;i<numLevels;i++)
{
        var skip =i*spacesPerLevel;     
        var subSpaces = spaces.Skip(start).Take(spacesPerLevel);
        var level = new Level(subSpaces);
        Add(level);
}

Effectively what you're creating is a paging algorithm, and since you're using List<T>, which implements IEnumerable<T>, you can take advantage of the Skip and Take methods.

Upvotes: 2

L.Trabacchin
L.Trabacchin

Reputation: 1620

You are removing the spaces from the collection, so you can't get the range you want because that range does not exist anymore, i suggest to use a queue instead of a list, dequeue the elements while you reach the maximum amount per level.

Will be a good exercise too.

foreach (var level in levels) {
    while(spaces.any() && level.spaces.count() <= maxPerLevel) {
        level.spaces.add (spaces.dequeue());
    }
}

You should also think to not evenly divisibile numbers, what if someone input 3 levels and 11 spaces?

Upvotes: 0

Jure
Jure

Reputation: 1176

Maybe you could try LINQ approach:

var count = 0;
var spacesPerLevel = spaces.Count / numLevels;
var levels = spaces
               .GroupBy(t => count++ / spacesPerLevel)
               .Select(t => new Level(new ParkingSpaces(t.ToList())))
               .ToList();
AddRange(levels);

Of course, there are few things to be aware of. Your Level constructor must take ParkingSpaces as an argument and your ParkingSpaces class constructor must take en IEnumerable<ParkingSpace> as an argument. LINQ expression will return List<Level>, which you can use in AddRange method for adding all levels at once.

Upvotes: 0

Pireax
Pireax

Reputation: 113

I think it's because of the RemoveRange call, thus decreasing the size of the list, thus the error. To fix this simply change the line with .GetRange to this:

ParkingSpaces subSpaces = spaces.GetRange(0, spacesPerLevel);

And the line where you call RemoveRange to this:

spaces.RemoveRange(0, spacesPerLevel);

Upvotes: 2

Related Questions