与列表进行快速字符串比较

时间:2009-07-20 12:02:15

标签: c# list string

我需要一个快速方法来确定给定字符串是否在字符串列表中。

直到运行时才知道字符串列表,但此后它不会改变。

我可以简单地使用名为List<String>的{​​{1}},然后执行:

strings

但是如果列表中有许多字符串,这将表现不佳。

我也可以使用if (strings.Contains(item)) ,但这需要在每个传入的字符串以及HashSet<String>上调用GetHashCode,如果存在例如{0},那将是一种浪费。列表中只有3个字符串。我是否提到这需要快速

我可以在设置时,根据字符串的数量决定使用EqualsList(例如,使用List少于10个字符串,否则使用HashSet),而不是像HashSet

由于字符串是unicode,标准的Trie结构不起作用,尽管Radix树/ Patricia trie可能。那里有基准测试的C#实现吗?

有些人提到绕过HybridDictionary的{​​{1}}并使用速度更快的哈希函数。那里有基准吗?

使用LINQ表达式实质上创建一个优化的switch语句是一种看起来非常有趣的新方法。

还有什么办法?设置成本并不重要,只是搜索速度。

如果重要,传入的字符串值很少会出现在列表中。

8 个答案:

答案 0 :(得分:5)

您可以使用trie来保存字符串列表;尝试是为快速重新 trie val而设计的。这是在{C#中实现trie的one example

更新Powerpoint presentation on folded tries for UnicodeIfo on implementation of a folded trie for Unicode (not C#)

答案 1 :(得分:3)

答案 2 :(得分:2)

您是否考虑过使用HashSet类(在.NET 3中)?

答案 3 :(得分:2)

关注你的“当名单很小”时;如果你不介意使用非泛型集合,System.Collections.Specialized.HybridDictionary会做这样的事情;它在小时封装System.Collections.Specialized.ListDictionary,或在变大时System.Collections.Hashtable封装>10。值得一看?


否则;您可以将HashSet<T>与自定义比较器一起使用吗?然后你可以选择GetHashCode()的价格是多少......

using System;
using System.Collections.Generic;

class CustomStringComparer : IEqualityComparer<string> {
    public bool Equals(string x, string y) {
        return string.Equals(x, y);
    }
    public int GetHashCode(string s) {
        return string.IsNullOrEmpty(s) ? 0 :
            s.Length + 273133 * (int)s[0];
    }
    private CustomStringComparer() { }
    public static readonly CustomStringComparer Default
        = new CustomStringComparer();
}
static class Program {
    static void Main() {
        HashSet<string> set = new HashSet<string>(
            new string[] { "abc", "def", "ghi" }, CustomStringComparer.Default);
        Console.WriteLine(set.Contains("abc"));
        Console.WriteLine(set.Contains("abcde"));
    }
}

答案 4 :(得分:2)

也许HybridDictionary是更好的选择。它的内部使用取决于集合中的项目数量。

答案 5 :(得分:2)

我最终这样做了:

private static bool Contains(List<string> list, string value)
{
    bool contains = null != list.Find(str => str.ToLower().Equals(value.ToLower()));

    return contains;
}

我猜你可以为List<string>创建一个扩展方法,但这足以满足我的需求。

答案 6 :(得分:0)

顺便说一下,如果内存服务,当构造一个String时,它的HashValue会被预先计算并与String一起存储,作为这种用例的优化。如果您正在使用字符数组或StringBuilder,这显然不适用,但对于不可变的String,它应该适用。

编辑:我不正确...... Java会缓存String的HashCode,而C#不会。

答案 7 :(得分:0)

您可以使用字符串实习来快速完成此操作。 构建列表时,必须存储所需字符串的实习格式(string.Intern()的结果)。然后,您需要使用object.ReferenceEquals与实习字符串进行比较 - 因为实习字符串具有相同的引用。

List<string> BuildList() {
    List<string> result;
    foreach (string str from StringSource())
         result.Add(str.Intern());
    return result;
}

bool CheckList(List<string> list, string stringToFind) { // list must be interned for this to work!
    return list.Find(str => object.ReferenceEquals(str, stringToFind)) != null;
}

这将导致每个列表进行四字节比较,并对原始字符串进行一次传递。实习字符串池专门用于快速字符串比较和查找是否已存在,因此实习操作应该非常快。