简体   繁体   中英

Searching Algorithms

Context

I've got a list of ordered (by name) City objects in memory, and I need to get a list of these cities as I type a character, a bit like a suggestion box.

Eg:

If a list has Madrid and Marseilles city names among others, when I press the 'M' character I need to get Madrid and Marseilles in the returned list. Well, in a couple of years back, I would be running a couple of threads, to make things go faster, but nowadays, with LINQ and TPL, and after a few tests, I've come to the conclusion that the faster way is to use these new libraries instead of doing it manually. As such I've written a few scripts and tested them against each other. Every code snipped runs in its own class:

//Snippet 1

            List<ICity> objCities = new List<ICity>();

            foreach (ICity objCity in this.m_objCities)
            {
                if (objCity.Name.Length >= pName.Length)
                {
                    if (objCity.Name.Substring(0, pName.Length).Equals(pName))
                    {
                        objCities.Add(objCity);
                    }
                }
                else if (objCitys.Count > 0)
                {
                    break;
                }
            }

            return objCities;

//Snippet 2

                ICollection<ICity> objCities = base.m_objCities.Where((ICity pCity) =>
            {
                bool bFound = false;

                if (pCity.Name.Length >= pName.Length)
                {
                    bFound = pCity.Name.Substring(0, pName.Length).Equals(pName);
                }

                return bFound;

            }).ToList();

            return objCities;

//Snippet 3

                ICollection<ICity> objCities = base.m_objCities.AsParallel().Where((ICity pCity) =>
            {
                bool bFound = false;

                if (pCity.Name.Length >= pName.Length)
                {
                    bFound = pCity.Name.Substring(0, pName.Length).Equals(pName);
                }

                return bFound;

            }).ToList();

            return objCities;

//Snippet 4

            //Used as a class member
            private List<ICollection<IStation>> objLastCities = new List<ICollection<IStation>>();

            int iNameCount = pName.Length;
            ICollection<ICity> objCities = null;

            if (this.m_iLastNameCount == 0 || iNameCount == 1)
            {
                objCities = base.m_objCities.Where((ICity pCity) =>
                                {
                                    bool bFound = false;

                                    if (pCity.Name.Length >= pName.Length)
                                    {
                                        bFound = pCity.Name.Substring(0, pName.Length).Equals(pName);
                                    }

                                    return bFound;

                                }).ToList();

                this.objLastCities.Clear();
                this.objLastCities.Add(objCities);

                this.m_iLastNameCount = 1;
            }
            else
            {
                if (iNameCount > this.m_iLastNameCount)
                {
                    objCities = this.objLastCities[this.m_iLastNameCount - 1].Where((ICity pCity) =>
                                {
                                    bool bFound = false;

                                    if (pCity.Name.Length >= pName.Length)
                                    {
                                        bFound = pCity.Name.Substring(0, pName.Length).Equals(pName);
                                    }

                                    return bFound;

                                }).ToList();

                    this.objLastCities.Add(objCities);

                    this.m_iLastNameCount++;
                }
                else
                {
                    objCities = base.m_objCities.Where((ICity pCity) =>
                                {
                                    bool bFound = false;

                                    if (pCity.Name.Length >= pName.Length)
                                    {
                                        bFound = pCity.Name.Substring(0, pName.Length).Equals(pName);
                                    }

                                    return bFound;

                                }).ToList();

                    this.objLastCities.RemoveAt(iNameCount - 1);

                    objCities = this.objLastCities[iNameCount - 1];

                    this.m_iLastNameCount--;
                }

                this.objLastCities.Add(objCities);
            }

            return this.objLastCities[this.objLastCities.Count - 1];

//Snippet 5

        ////Member objects
        private List<ICollection<ICity>> objLastCities = new List<ICollection<ICity>>();
        private int m_iLastNameCount = 0;
        private Dictionary<char, ICollection<ICity>> m_objCitiesByKey = null;


        ////Code that runs in the class contructor
        this.m_objCitiesByKey.Add('A', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'A'; }).ToList());
        this.m_objCitiesByKey.Add('B', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'B'; }).ToList());
        this.m_objCitiesByKey.Add('C', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'C'; }).ToList());
        this.m_objCitiesByKey.Add('D', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'D'; }).ToList());
        this.m_objCitiesByKey.Add('E', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'E'; }).ToList());
        this.m_objCitiesByKey.Add('F', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'F'; }).ToList());
        this.m_objCitiesByKey.Add('G', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'G'; }).ToList());
        this.m_objCitiesByKey.Add('H', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'H'; }).ToList());
        this.m_objCitiesByKey.Add('I', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'I'; }).ToList());
        this.m_objCitiesByKey.Add('J', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'J'; }).ToList());
        this.m_objCitiesByKey.Add('K', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'K'; }).ToList());
        this.m_objCitiesByKey.Add('L', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'L'; }).ToList());
        this.m_objCitiesByKey.Add('M', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'M'; }).ToList());
        this.m_objCitiesByKey.Add('N', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'N'; }).ToList());
        this.m_objCitiesByKey.Add('O', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'O'; }).ToList());
        this.m_objCitiesByKey.Add('P', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'P'; }).ToList());
        this.m_objCitiesByKey.Add('Q', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'Q'; }).ToList());
        this.m_objCitiesByKey.Add('R', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'R'; }).ToList());
        this.m_objCitiesByKey.Add('S', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'S'; }).ToList());
        this.m_objCitiesByKey.Add('T', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'T'; }).ToList());
        this.m_objCitiesByKey.Add('U', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'U'; }).ToList());
        this.m_objCitiesByKey.Add('V', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'V'; }).ToList());
        this.m_objCitiesByKey.Add('W', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'W'; }).ToList());
        this.m_objCitiesByKey.Add('X', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'X'; }).ToList());
        this.m_objCitiesByKey.Add('Y', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'Y'; }).ToList());
        this.m_objCitiesByKey.Add('Z', base.m_objCities.Where((ICity pCity) => { return pCity.Name[0] == 'Z'; }).ToList());


        ////Code Running in a Methods
        int iNameCount = pName.Length;
        ICollection<ICity> objCities = null;

        if (this.m_iLastNameCount == 0 || iNameCount == 1)
        {
            objCities = this.m_objCitiesByKey[pName[0]];

            this.objLastCities.Clear();
            this.objLastCities.Add(objCities);

            this.m_iLastNameCount = 1;
        }
        else
        {
            if (iNameCount > this.m_iLastNameCount)
            {
                objCities = this.objLastCities[this.m_iLastNameCount - 1].Where((ICity pCity) =>
                                                                            {
                                                                                bool bFound = false;

                                                                                if (pCity.Name.Length >= pName.Length)
                                                                                {
                                                                                    bFound = pCity.Name.Substring(0, pName.Length).Equals(pName);
                                                                                }

                                                                                return bFound;

                                                                            }).ToList();

                this.objLastCities.Add(objCities);

                this.m_iLastNameCount++;
            }
            else
            {
                objCities = base.m_objCities.Where((ICity pCity) =>
                                                                            {
                                                                                bool bFound = false;

                                                                                if (pCity.Name.Length >= pName.Length)
                                                                                {
                                                                                    bFound = pCity.Name.Substring(0, pName.Length).Equals(pName);
                                                                                }

                                                                                return bFound;

                                                                            }).ToList();


                this.objLastCities.RemoveAt(iNameCount - 1);

                objCities = this.objLastCities[iNameCount - 1];

                this.m_iLastNameCount--;
            }

            this.objLastCities.Add(objCities);
        }

        return this.objLastCities[this.objLastCities.Count - 1];

Based on the result I get with the aid of the Stopwatch class, the faster script is the number 4, but I was expecting it to be number 5, given that all the cities are split in the dictionary, but unfortunately the dictionary class seems to be way to slow.

So do you guys see any way to improve the performance here?

Thanks

Have you tried using a trie ? you can given the first n letters to search for find the subtrie representing the list in n operations and then convert it into a list in parallel

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