Migrating data using entity framework, linq and recursion I have a piece of code to migrate data from an old app to a new app. The data represents the user's websites. 

In the old app the user only had one section for websites, on which you could add any website, even social links. 

In the new app, the user can add personal websites, social links (only Facebook, Twitter and LinkedIn are considered social links) and what we call custom social networks (eg. Reddit, Meetup, Tumblr, etc)

This is the code:

public async Task ImportWebsites(int userId)
{
    string[] socialNetworksStr =
    {
        "linkedin.",
        "twitter.",
        "facebook.",
    };

    string[] customSocialNetworksStr = 
    {   "deviantart.",
        "viadeo.",
        "reddit.",
        "xing.",
        "pinterest.",
        "tumblr.",
    };

    List&lt;UserLinkDTO&gt; personalWebsites = new List&lt;UserLinkDTO&gt;();
    List&lt;UserSocialNetworkDTO&gt; socialNetworks = new List&lt;UserSocialNetworkDTO&gt;();
    List&lt;UserLinkDTO&gt; customSocialNetworks = new List&lt;UserLinkDTO&gt;();
    List&lt;UserLinkDTO&gt; personalWebsitesRemoved = new List&lt;UserLinkDTO&gt;();


    using (OldContext ctx = new OldContext())
    {
        if (await (ctx.UserSettings.AnyAsync(u =&gt; u.UserId == userId)) == false)
            throw new RelatedEntityNotFoundException($"{userId} not be found!");

        personalWebsites = await ctx.PersonalWebsite.AsNoTracking()
                                    .Where(w =&gt; w.UserId == userId)
                                    .Select(w =&gt; new UserLinkDTO
                                    {
                                        UserId = w.UserId,
                                        Description = w.PersonalWebsiteDescription,
                                        Url = w.PersonalWebsiteURL,
                                        Name = w.PersonalWebsiteName
                                    }).ToListAsync().ConfigureAwait(false);
    }

    for (int i = 0; i &lt; personalWebsites.Count; i++)
    {
        string url = personalWebsites[i].Url;
        if (!url.StartsWith("http://"))
        {
            personalWebsites[i].Url = "http://" + url;
        }
    }

    if (personalWebsites.Any())
    {
        foreach (var personalWebsite in personalWebsites)
        {
            foreach (var socialNetwork in socialNetworksStr)
            {
                if (personalWebsite.Url.Contains(socialNetwork))
                {
                    socialNetworks.Add(new UserSocialNetworkDTO() {
                        SocialNetworkId = (short)(Array.IndexOf(socialNetworksStr, socialNetwork) + 1),
                        Account = personalWebsite.Url
                    });
                    personalWebsitesRemoved.Add(personalWebsite);
                }
            }
            foreach (var customSocialNetwork in customSocialNetworksStr)
            {
                if (personalWebsite.Url.Contains(customSocialNetwork))
                {
                    customSocialNetworks.Add(personalWebsite);
                    personalWebsitesRemoved.Add(personalWebsite);
                }
            }
        }

        personalWebsites = personalWebsites.Except(personalWebsitesRemoved).ToList();
        var personalInfo = await PersonalInfoService.GetPersonalInfo(userId);

        personalInfo.Result.PersonalWebsites = personalWebsites;
        if(socialNetworks.Any()) personalInfo.Result.SocialNetworks = socialNetworks;
        if(customSocialNetworks.Any()) personalInfo.Result.CustomSocialNetworks = customSocialNetworks;

        var response = await PersonalInfoService.SavePersonalInfo(personalInfo.Result);
    }
}

    var response = await PersonalInfoService.SavePersonalInfo(personalInfo.Result);
}


My code does its job, but it takes some time, on those foreaches, and I think it's a little bit redundant, and I think it may be optimzed. How would you improve this?

PS I think I included all the necessary info, sorry If I forgot something.
The following code is O(n^2). More precisely, it's Theta(n^2) because it'll always be exactly n.

foreach (var personalWebsite in personalWebsites)
{
    // You can use a HashSet to eliminate the need for the inner loops, which
    // would reduce your computational complexity from Theta(n^2) to Theta(n) - see below
    foreach (var socialNetwork in socialNetworksStr)
    {
        // You could "convert" both of these to some kind of "normal form" (see below) to eliminate the need for the relatively inefficient "Contains" and enable the use of a HashSet
        if (personalWebsite.Url.Contains(socialNetwork))
        {
            socialNetworks.Add(new UserSocialNetworkDTO() { SocialNetworkId = (short)(Array.IndexOf(socialNetworksStr, socialNetwork) + 1), Account = personalWebsite.Url });
            personalWebsitesRemoved.Add(personalWebsite);

            // If you do stick with a loop here, presumably each personal web site only
            // matches one social media site, so you can break out of the loop here to
            // improve your computational complexity for this bit from Theta(n) to O(n)
        }
    }

    // Same comments as above
    foreach (var customSocialNetwork in customSocialNetworksStr)
    {
        if (personalWebsite.Url.Contains(customSocialNetwork))
        {
            customSocialNetworks.Add(personalWebsite);
            personalWebsitesRemoved.Add(personalWebsite);
        }
    }


You can reduce this to O(n) by reducing the URLs to some kind of "normal form" (e.g. http://www.linkedin.com/in/some.person would just be "normalized" to "linkedin.com") and building a Dictionary (hash table) or HashSet. This would reduce the computational complexity from Theta(n^2) to Theta(n).

Also, even if you do stick with the "inner" foreach loops, there's no need to iterate over all of the social network sites every single time; I assume that each personal web site can only match one social media site, so if you find one that it matches it reduces the computational complexity from Theta(n^2) to O(n^2).