簡體   English   中英

C# 確定字符串是否包含列表所有元素的最快方法

[英]C# Fastest way to determine if a string contains all elements of a list

快速背景。 我有一串單詞 - 我將這些單詞分成一個列表(我已經嘗試過 HashSet 它沒有任何區別 - 你失去了列表的有序性質)。

然后我以許多枯燥的方式操縱原始單詞 - 並創建數千個“新字符串” - 所有這些字符串都在已設置的StringBuilder.ToString();

在操作結束時,我想 QC 那些新字符串 - 並確保原始集合中的每個單詞 - 仍然在這些新字符串中的某個位置,並且我沒有意外丟失一個單詞。

那個原始字符串,可以運行到數百個單獨的單詞。

簡短的例子:

List<string> uniqueWords = new List<string> { "two", "three", "weather sunday" };

string final = "two and tomorrow\n\rtwo or wednesday\n\rtwo with thursday\n\rtwo without friday\n\rthree gone tomorrow\n\rthree weather saturday\n\rthree timely sunday";

output 字符串可以運行到數千萬個字符、數百萬個單詞、200,000+ 行數據(拆分時)。 您可能會注意到有些單詞實際上是由空格分隔的兩個單詞 - 所以我不能簡單地通過在空格上拆分來拆分單個單詞,因為將它們與原始單詞進行比較會失敗,我需要確認單詞完全一樣出於我的目的,它們最初出現 - 在某處有天氣,在某處有星期天 - 與有“星期天天氣”不同。

到目前為止我嘗試過並進行了基准測試的代碼:

第一次嘗試:

var allWords = uniqueWords.Where(substring => final.Contains(substring, StringComparison.CurrentCultureIgnoreCase)).ToList();

第二次嘗試:

List<string> removeableList = new(uniqueWords);
foreach (var item in uniqueWords)
{
    if (removeableList.Count == 0)
    {
        break;
    }
    if (final.Contains(item))
    {
        removeableList.Remove(item);
    }
}

第三次嘗試:

List<string> removeableList = new(uniqueWords);
for (int i = uniqueWords.Count; i >= 0; i--)
{
    if (removeableList.Count == 0)
    {
        break;
    }
    if (final.Contains(uniqueWords[i]))
    {
        removeableList.Remove(uniqueWords[i]);
    }
}

這些是結果:

在此處輸入圖像描述

這些結果是可重復的,盡管我會說第一次嘗試往往波動很大,而第二次和第三次嘗試往往保持在相同的水平 - 第三次嘗試似乎確實比第二次做得更好,相當一致。

我有什么選擇嗎?

我已經嘗試使用 Regex Matches 集合到 HashSet 中 - 哦,這很糟糕,比第一次嘗試差 4 倍。

如果有辦法提高這項任務的性能,我很想找到它。

您的嘗試 #1 使用CurrentCultureIgnoreCase會很慢。 但即使在刪除它之后,您也會添加到列表中,而不是刪除,因此可能需要調整列表的大小。

您還測量了兩個不同的東西:選項#1獲取final單詞列表,其他選項獲取單詞列表。

其他選項包括:

  • 使用List.RemoveAll
List<string> remainingWords = new(uniqueWords);
remainingWords.RemoveAll(final.Contains);   // use delegate directly, without anonymous delegate
  • 使用預先確定的列表並使用 Linq
List<string> remainingWords = new(uniqueWords.Length);
remainingWords.AddRange(uniqueWords.Where(s => !final.Contains(s)));

如前所述,這兩個選項中的每一個都可以根據您要達到的結果進行翻轉。

List<string> words = new(uniqueWords);
words.RemoveAll(s => !final.Contains(s));
List<string> words = new(uniqueWords.Length);
words.AddRange(uniqueWords.Where(final.Contains));   // use delegate directly, without anonymous delegate

@Charlieface,謝謝 - 我試過了,我認為你有一點關於添加到列表中 - 因為這看起來要慢得多。 對我來說,添加還是刪除都沒有關系,結果是 True/False 返回 - 列表是空的還是原始列表的大小。

第六次嘗試:

List<string> removeableList = new(uniqueWords.Count);
removeableList.AddRange(uniqueWords.Where(s => !parsedTermsComplete!.Contains(s)));

第七次嘗試:

List<string> removeableList = new(uniqueWords);
removeableList.RemoveAll(parsedTermsComplete!.Contains);

與第三次嘗試相比的結果(通常最快):

在此處輸入圖像描述

添加確實顯得較慢 - 並且 memory 對於 RemoveAll 稍高,但時間是一致的 - 請記住,它會根據 Windows 在任何給定時刻決定做什么而波動......

這是 AhoCorasickTree 方法的一個有趣的實現——我在這個網站的其他地方看到過它。

My knowledge on this is extremely limited so this may not be a good implementation at all - I am not saying it is a good implementation just that it works - this comes from a nuget package, but I am unsure on SO's policy on nuget package links ,所以暫時不鏈接。 在測試中,創建數組比創建列表更快。

第八次嘗試:

var wordArray = uniqueWords.ToArray();
int i = uniqueWords.Count - 1;
foreach (var item in wordArray)
{
    var keyWords = new AhoCorasickTree(new[] { item });
    if (keyWords.Contains(parsedTermsComplete))
    {
        uniqueWords.RemoveAt(i);
    }
    i--;
}

我在測試中注意到創建“removableList”實際上比創建removableArray 慢(發現這是實現上述Aho 運行)。 我更新了第三次嘗試以將其合並:

var removeableArray = uniqueWords.ToArray();
for (int i = removeableArray.Length -1; i >= 0; i--)
{
    if (!uniqueWords.Any())
    {
        break;
    }
    if (parsedTermsComplete!.Contains(removeableArray[i]))
    {
        uniqueWords.RemoveAt(i);
    }
}

基准測試是這樣出來的,第三次嘗試更新為數組,第七次嘗試是列表上的 AhoCorasick 實現,第八次嘗試是數組上的 AhoCorasick 實現。

在此處輸入圖像描述

ToArray - 看起來確實比 List 快,這很高興知道。

我對 AhoCorasick 的唯一問題是在實踐中 - 在 WASM 應用程序中 - 這實際上要慢得多,所以對我來說不是一個好選擇 - 但我把它放在這里是因為它在基准測試中似乎要快得多(可能使用多個WASM 限制為 1) 並且似乎沒有分配任何 memory 的線程,因此可能對某人有用 - 有趣的是,在使用 Array 實現時,第三次嘗試似乎也沒有分配 memory,而在列表中分配了它。

暫無
暫無

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

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