简体   繁体   中英

Refactor function so that it is O(N)

I fetch a bunch of categories for a dropdow tree, and have to implement search in this dropdown. If there is a match in one of the elements, it should also get all parents to display in the dropdown hierarchy.

I started with 2 foreach loops where I filtered out the matches, and one where I check the matches for parentId and recursive add the parents untill there are none left ( parentId == 0 ).

public ScrapCategory[] Filter(ScrapCategory[] categories, string searchString)
{
    var result = new List<ScrapCategory>();

    foreach (ScrapCategory category in categories)
    {
        if (category.Description.IndexOf(searchString, StringComparison.OrdinalIgnoreCase) >= 0)
            result.Add(category);

        if (category.ParentId == 0)
            continue;

        ScrapCategory currentParent = categories.Where(x => x.Id == category.ParentId).First();

        if (!result.Contains(currentParent))
            result.Add(currentParent);

        while (currentParent?.ParentId > 0)
        {
            currentParent = categories.Where(x => x.Id == currentParent.ParentId)?.First();
            if (!result.Contains(currentParent))
                result.Add(currentParent);
        }
    }

    return result.OrderBy(x => x.Level).ToArray();
}

I get the expected result but I would love to see this in O(N), so only one interation over the categories without those .Where() clauses.

Edit: I managed to get rid of one .Where() clause.

 public ScrapCategory[] Filter(ScrapCategory[] categories, string searchString)
        {
            var result = new List<ScrapCategory>();

            foreach (ScrapCategory category in categories)
            {
                if (category.Description.IndexOf(searchString, StringComparison.OrdinalIgnoreCase) >= 0)
                    result.Add(category);

                if (category.ParentId > 0)
                {
                    int parentId = category.ParentId;

                    while (parentId > 0)
                    {
                        var parent = categories.Where(x => x.Id == parentId)?.First();
                        if (!result.Contains(parent))
                            result.Add(parent);
                        parentId = parent.ParentId;
                    }
                }
            }

            return result.OrderBy(x => x.Level).ToArray();
        }

This is my final result, and I'm happy with it.

public ScrapCategory[] Filter(ScrapCategory[] categories, string searchString)
    {
        var lookup = categories.ToDictionary(category => category.Id);
        var result = new HashSet<ScrapCategory>();
        foreach (ScrapCategory category in categories)
        {
            if (category.Description.IndexOf(searchString, StringComparison.OrdinalIgnoreCase) >= 0)
                result.Add(category);
            int parentId = category.ParentId;
            while (parentId > 0)
            {
                ScrapCategory parent = lookup[parentId];
                if (!result.Add(parent))
                    break;
                parentId = parent.ParentId;
            }
        }
        return result.OrderBy(n => n.Level).ToArray();
    }

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