简体   繁体   中英

C# Optimize nested foreach loops

I've written an Library which works with a large excel and maps the entries into objects. But at some point it becomes really slow due to three nested foreach loops. I've seen some solutions with an dictionary but the problem there was a bit different as mine.

var house = new PostHouse();
house.FK_STRID = long.Parse(fields[2]);
if (!fields[3].Equals("")){
     house.HouseNumber = long.Parse(fields[3]);
}
foreach (var canton in cantons)
{
    foreach(var city in canton.Cities)
    {
        if (city.Streets == null) 
            city.Streets = new List<PostStreet>();
        foreach(var street in city.Streets)
        {
            if(street.STRID == house.FK_STRID)
            {
                if (street.Houses == null) 
                    street.Houses = new List<PostHouse>();
                street.Houses.Add(house);
            }
        }
    }
}

It takes about 10 minute to loop over everything.

Any help?

Thanks in advance

It's hard to say because we don't know what type cantons and its children are and where they come from, but the main issue here is that you have a data structure that's not suited for the task. You have a hierarchical list of Streets inside Cities inside Cantons, when what you need is a list of Streets indexed by their STRID.

If you can do initial processing of how your streets are stored, you can do this:

var streetIndex = new Dictionary<string, PostStreet>();
foreach (var canton in cantons)
  foreach (var city in canton.Cities)
    foreach (var street in city.Streets)
    { 
        streetIndex.Add(street.STRID, street);
    }

then you can instantly look up a street by its STRID when you're iterating over houses in O(1) time.

foreach (var house in houses)
{
    if (streetIndex.ContainsKey(house.FK_STRID))
    {
       streetIndex[house.FK_STRID].Add(house);   
    }
}

Do this stuff in your constructors or auto initliaize them

Streets = new List<PostStreet>();

...

Houses = new List<PostHouse>()

Then Linq

var streets = cantons.SelectMany(x => x.Cities)
                     .SelectMany(x => x.Streets)
                     .Where(x => x.STRID == house.FK_STRI);


foreach (var street in streets)
    street.Houses.Add(house);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM