簡體   English   中英

過濾單詞列表的最快方法

[英]Quickest way to filter a list of words

我有一個包含幾個單詞的列表。 我想過濾掉其中一些與特定模式不匹配的內容。 是否可以更快地將所有匹配項添加到臨時列表中,然后將此列表復制到主列表中? 或者更快地從主列表中刪除所有不匹配? 我必須盡快過濾10000個單詞,所以我期待每一個小小的速度提升。

編輯:

string characters = "aAbBcC";
// currentMatches contains all the words from the beginning
List<string> currentMatches = new List<string>();
List<string> newMatches = new List<string>();
foreach (string word in currentMatches)
{
   if (characters.IndexOf(word[0]) > -1)
   // word match
   {
       newMatches.Add(word);
   }
}
currentMatches = newMatches;

foreach循環還應當檢查是否word用的字符中的一個開頭characters 在將所有新匹配復制到newMatches之前,我將每個匹配復制到currentMatches

假設List<T>那么你將不得不考慮以下內容:

  • 如果Count小於Capacity,則Add方法是O(1)操作。 如果需要增加容量以容納新元素,則此方法變為O(n)操作,其中n為Count;
  • RemoveAt方法是一個O(n)操作,其中n是(Count - index)。

如果您創建列表以保持匹配的初始容量設置為總字數,則Add將始終為O(1)且更快。 但是,您需要考慮創建此新列表的開銷,其容量設置為總字數。

最重要的是,您需要對其進行測試,看看哪種方法更適合您的特定場景。

這是一個我如何計算時間方法的例子。 有很多方法可以做到這一點,我想你將不得不嘗試一些。 您可以使用JoãoAngelo的帖子中的信息來幫助您找到好的方法,但這里有一些。 此外,如果您願意花時間,可以將這一切放在一個循環中,創建一個新列表,運行所有測試,將TimeSpan結果放入集合而不是Console.WriteLine'ing它們,以及然后給你一個平均但是多次迭代的測試。 這將有助於給你一個平均值。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Test
{
    public class Program
    {
        public static void Main(string[] args)
        {
            List<string> testList = CreateTestList();
            const string filter = "abc";

            TimeNewListMethod(FilterIntoNewListWithLinq, testList, filter);
            TimeInPlaceMethod(FilterInPlaceWithLinq, testList, filter);

            TimeNewListMethod(FilterIntoNewListWithForEach, testList, filter);

            TimeInPlaceMethod(FilterInPlaceWithRemoveAll, testList, filter);

            Console.Read();
        }

        public static void TimeInPlaceMethod(Action<List<string>, string> testMethod, List<string> toFilter, string filter)
        {
            List<string> toFilterCopy = new List<string>(toFilter);
            DateTime time = DateTime.Now;
            testMethod(toFilterCopy, filter);
            Console.WriteLine(DateTime.Now - time);
        }

        public static void TimeNewListMethod(Func<List<string>, string, List<string>> testMethod, List<string> toFilter, string filter)
        {
            List<string> toFilterCopy = new List<string>(toFilter);
            List<string> resultList;
            DateTime time = DateTime.Now;
            resultList = testMethod(toFilterCopy, filter);
            Console.WriteLine(DateTime.Now - time);
        }

        public static List<string> FilterIntoNewListWithLinq(List<string> toFilter, string filter)
        {
            return toFilter.Where(element => element.IndexOf(filter) > -1).ToList();
        }

        public static void FilterInPlaceWithLinq(List<string> toFilter, string filter)
        {
            toFilter = toFilter.Where(element => element.IndexOf(filter) > -1).ToList();
        }

        public static List<string> FilterIntoNewListWithForEach(List<string> toFilter, string filter)
        {
            List<string> returnList = new List<string>(toFilter.Count);
            foreach (string word in toFilter)
            {
                if (word.IndexOf(word[0]) > -1)
                {
                    returnList.Add(word);
                }
            }

            return returnList;
        }

        public static void FilterInPlaceWithRemoveAll(List<string> toFilter, string filter)
        {
            toFilter.RemoveAll(element => element.IndexOf(filter) == -1);
        }

        public static List<string> CreateTestList(int elements = 10000, int wordLength = 6)
        {
            List<string> returnList = new List<string>();
            StringBuilder nextWord = new StringBuilder();

            for (int i = 0; i < elements; i++)
            {
                for (int j = 0; j < wordLength; j++)
                {
                    nextWord.Append(RandomCharacter());
                }
                returnList.Add(nextWord.ToString());
                nextWord.Clear();
            }

            return returnList;
        }

        public static char RandomCharacter()
        {
            return (char)('a' + rand.Next(0, 25));
        }

        public static Random rand = new Random();
    }
}

整體

characters.IndexOf(word [0])> -1

對我來說有點陌生,所以我會為未來的程序員尋找更具可讀性和可維護性的東西。 我花了一分鍾才弄清楚你正在檢查列表中每個字符串中的第一個字符,以查找{a A,B,C,a,b,c}范圍內的匹配項。 它有效,但對我來說,它有點神秘。 我開始花時間閱讀它,但我會這樣做:

        foreach (string word in currentMatches)
        {               
            if (Regex.IsMatch(word, "^([A-Ca-c])"))
            {
                newMatches.Add(word);
            }
        }

我不擔心將臨時列表復制回初始列表。 你已經定義它填充它,繼續使用它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM