通过StartsWith和EndsWith查询通过LINQ选择字符串列表时,如何保持字符串数据以获得最佳性能

本文关键字:字符串 何保持 数据 性能 最佳 列表 EndsWith StartsWith 查询 选择 LINQ | 更新日期: 2023-09-27 18:25:26

现在这个问题很难回答。我有一个类似下面方式的linq查询

var lstSimilars = from similarWords in lstAllWords
where similarWords.StartsWith(srWordLocal)
select similarWords;
foreach (string srVar in lstSimilars)
{
string srTempWord = srVar.Replace(srWordLocal, "");
if (dtWords.ContainsKey(srTempWord) == true)
{
csWords.updateSplitWord(srWordLocal + ";" + srTempWord, dtWords[srVar]);
}
}
lstSimilars = from similarWords in lstAllWords
where similarWords.EndsWith(srWordLocal)
select similarWords;
foreach (string srVar in lstSimilars)
{
string srTempWord = srVar.Replace(srWordLocal, "");
if (dtWords.ContainsKey(srTempWord) == true)
{
csWords.updateSplitWord(srWordLocal + ";" + srTempWord, dtWords[srVar]);
}
}

现在lstAllWords是一个字符串列表变量,生成方式与类似

        List<string> lstAllWords = new List<string>();

        for (int i = 0; i < dsWordsSplit.Tables[0].Rows.Count; i++)
        {
            lstAllWords.Add(dsWordsSplit.Tables[0].Rows[i]["Word"].ToString());
        }

我的问题是,我应该如何保存Words数据以获得最佳LINQ选择性能。我的意思是,目前我把它作为一个字符串列表。但我能保持不同的方式并有更好的表现吗?

dtWords是字典对象

C#C#-4.0 LINQ

通过StartsWith和EndsWith查询通过LINQ选择字符串列表时,如何保持字符串数据以获得最佳性能

如果您只想有效地查找以给定子字符串开头或结尾的单词,那么使用SortedSet将帮助您在O(log(N))时间内做到这一点。

这个想法是把单词放在两个SortedSet中:

  • 一个用于原始单词和
  • 另一个表示颠倒的单词

玩具实施:

class WordSet {
    public WordSet(IEnumerable<string> words) {
        m_OriginalWords = new SortedSet<string>(words);
        m_ReverseWords = new SortedSet<string>(words.Select(ReverseString));
    }
    /// <summary>
    ///     Finds all words that start with given prefix.
    /// </summary>
    public IEnumerable<string> FindPrefix(string prefix) {
        return FindImp(m_OriginalWords, prefix);
    }
    /// <summary>
    ///     Finds all words that end with the given suffix.
    /// </summary>
    public IEnumerable<string> FindSuffix(string suffix) {
        return FindImp(m_ReverseWords, ReverseString(suffix)).Select(ReverseString);
    }
    static IEnumerable<string> FindImp(SortedSet<string> word_set, string s) {
        if (s.CompareTo(word_set.Max) <= 0) {
            foreach (string word in word_set.GetViewBetween(s, word_set.Max)) {
                if (!word.StartsWith(s))
                    break;
                yield return word;
            }
        }
    }
    static string ReverseString(string src) {
        return new string(src.Reverse().ToArray());
    }
    readonly SortedSet<string> m_OriginalWords;
    readonly SortedSet<string> m_ReverseWords;
}
class Program {
    static void TestImp(string s, IEnumerable<string> words) {
        Console.Write(s);
        foreach (var word in words) {
            Console.Write(''t');
            Console.Write(word);
        }
        Console.WriteLine();
    }
    static void TestPrefix(WordSet word_set, string prefix) {
        TestImp(prefix, word_set.FindPrefix(prefix));
    }
    static void TestSuffix(WordSet word_set, string suffix) {
        TestImp(suffix, word_set.FindSuffix(suffix));
    }
    static void Main(string[] args) {
        var word_set = new WordSet(
            new[] {
                "a",
                "b",
                "ba",
                "baa",
                "bab",
                "bba",
                "bbb",
                "bbc",
            }
        );
        Console.WriteLine("Prefixes:");
        TestPrefix(word_set, "a");
        TestPrefix(word_set, "b");
        TestPrefix(word_set, "ba");
        TestPrefix(word_set, "bb");
        TestPrefix(word_set, "bc");
        Console.WriteLine("'nSuffixes:");
        TestSuffix(word_set, "a");
        TestSuffix(word_set, "b");
        TestSuffix(word_set, "ba");
        TestSuffix(word_set, "bb");
        TestSuffix(word_set, "bc");
    }
}

此打印:

Prefixes:
a       a
b       b       ba      baa     bab     bba     bbb     bbc
ba      ba      baa     bab
bb      bba     bbb     bbc
bc
Suffixes:
a       a       baa     ba      bba
b       b       bab     bbb
ba      ba      bba
bb      bbb
bc      bbc

如果你也必须搜索中缀,那么以上是不够的——你需要一个后缀树或数组,但这不是一件容易的事,可以有效地正确实现


顺便说一句,如果数据恰好在数据库中,你可以让DBMS做基本上相同的事情:

  • 创建与原始单词列相反的计算列或虚拟列
  • 索引原始单词列和反向单词列(或者,如果DBMS支持,则使用基于函数的索引)
  • 查询前缀为:ORIGINAL_WORD_COLUMN LIKE 'pefix%'
  • 后缀为:REVERSED_WORD_COLUMN LIKE 'reversed_suffix%'

字符串列表应该具有足够的性能,可以从中进行选择,但您要添加一些装箱/取消装箱操作,方法是将其选择到var中,然后对其进行迭代。为了提高性能,您可以使用强类型List<string>作为LINQ查询结果的接收者,但它可能只在非常的大型数据集中才明显。