C# c中比较对象的最快方法#

C# c中比较对象的最快方法#,c#,performance,C#,Performance,我正在编写一个验证某些城市的应用程序。验证的一部分是通过匹配国家代码和cityname(或alt cityname)来检查城市是否已经在列表中 我将现有城市列表存储为: public struct City { public int id; public string countrycode; public string name; public string altName; public int timezoneId; } List<City&

我正在编写一个验证某些城市的应用程序。验证的一部分是通过匹配国家代码和cityname(或alt cityname)来检查城市是否已经在列表中

我将现有城市列表存储为:

public struct City
{
    public int id;
    public string countrycode;
    public string name;
    public string altName;
    public int timezoneId;
}

List<City> cityCache = new List<City>();
这对于很多记录来说是非常缓慢的,因为我也以同样的方式检查其他对象,如机场和国家。我有没有办法加快速度?这种比较是否有比List更快的集合,是否有比FirsOrDefault()更快的比较函数

编辑

我忘记发布我的Like()函数:

bool Like(string s1, string s2)
    {
        if (string.IsNullOrEmpty(s1) || string.IsNullOrEmpty(s2))
            return s1 == s2;
        if (s1.ToLower().Trim() == s2.ToLower().Trim())
            return true;

        return Regex.IsMatch(Regex.Escape(s1.ToLower().Trim()), Regex.Escape(s2.ToLower().Trim()) + ".");
    }

我会为CityString和CountryCode使用哈希集。 差不多

var validCountryCode = new HashSet<string>(StringComparison.OrdinalIgnoreCase);
if (validCountryCode.Contains(city.CountryCode))
{
}
var validCountryCode=新哈希集(StringComparison.OrdinalIgnoreCase);
if(validCountryCode.Contains(city.CountryCode))
{
}
等等

我个人会在构造函数中进行所有验证,以确保只有有效的城市对象存在

其他需要注意的事项

  • 如果要在有效列表中查找,请使用HashSet
  • 在适当的情况下使用IEqualityComparer,重用对象以避免构建/GC成本
  • 使用字典查找任何需要查找的内容(例如timeZoneId)
  • 编辑1

    你是cityCache可能是这样的

    var cityCache = new Dictionary<string, Dictionary<string, int>>();
    var countryCode = "";
    var cityCode = "";
    var id = x;
    
    public static IsCityValid(City c)
    {
         return
             cityCache.ContainsKey(c.CountryCode) &&
             cityCache[c.CountryCode].ContainsKey(c.CityCode) &&
             cityCache[c.CountryCode][c.CityCode] == c.Id;  
    }
    
    var cityCache=new Dictionary();
    var countryCode=“”;
    var cityCode=“”;
    var id=x;
    公共静态IsCityValid(c市)
    {
    返回
    cityCache.ContainsKey(c.CountryCode)&&
    cityCache[c.CountryCode]。ContainesKey(c.CityCode)&&
    cityCache[c.CountryCode][c.CityCode]==c.Id;
    }
    
    编辑2

    我不认为我必须解释这一点,但根据评论,也许

    FirstOrDefault()
    是一个O(n)操作。基本上,每次你试图在列表中查找某个内容时,你可以是幸运的,它是列表中的第一个,也可以是不幸的,它是列表的最后一个平均值。计数/2。另一方面,字典将是O(1)查找。使用IEqualtiyComparer,它将生成一个HashCode(),并查找它所在的bucket。如果只有大量的碰撞,那么它将使用Equals在同一个bucket中的事物列表中查找您要查找的内容。即使HashCode()质量很差(总是返回相同的HashCode),因为
    字典
    /
    哈希集
    使用素数存储桶,您也会将列表拆分,从而减少需要完成的相等数

    因此,列出10个对象意味着您平均运行了5次。
    一个包含以下10个相同对象的字典(取决于哈希代码的质量),可以是一个
    HashCode()
    调用,然后是一个
    Equals()
    调用。

    这听起来像是一个很好的二叉树候选

    有关.NET中的二叉树实现,请参阅:

    编辑:
    如果您想快速搜索一个集合,并且该集合特别大,那么最好的选择是对其进行排序,并基于该排序实现搜索算法

    当您希望快速搜索并相对不频繁地插入项目时,二叉树是一个很好的选择。不过,为了保持搜索速度,您需要使用平衡二叉树

    不过,要使其正常工作,您还需要一个用于城市的标准密钥。数字键最好,但字符串也可以很好地工作。如果您将城市与其他信息(如州和国家)连接起来,您将获得一个很好的唯一密钥。您还可以将大小写更改为全部大写或小写,以获得不区分大小写的密钥

    如果没有密钥,则无法对数据进行排序。如果您不能对数据进行排序,那么就不会有很多“快速”选项

    编辑2:

    我注意到Like函数经常编辑字符串。编辑字符串是一项极其昂贵的操作。最好在首次加载数据时执行一次
    ToLower()
    Trim()
    函数。这可能会大大加快您的功能。

    我认为您最大的性能问题是使用
    之类的
    操作符,这很昂贵。你不能简单地使用一个相等比较器吗?你能告诉我们你是如何调用这个比较方法的吗?出于几个原因,我建议不要在内存中这样做。首先是因为您已经看到这种机制存在明显的性能问题,但第二是因为您在内存中保存了大量信息,只是为了搜索它。这在数据库服务器上非常合适,往返费用非常小。是否有一个城市的cannonical表示?正如M Afifi所说,哈希集会快得多。但是,您需要注意的是,名称的任何细微变化都应该对应于同一个城市。@Mike-我在问题或评论中没有看到任何提到数据库的地方。为什么假设有一个附加的数据库?请注意,代码使用Like运算符-除非发生更改,否则此代码将无法工作。通过将正确的IEqualityComparer传递到字典中,可以轻松修复此问题。如果实现正确,ContainsKey将与您所追求的匹配。因此,如果您在那里实现类似的操作,您就不会解决性能问题-是吗?这显然是一个非常大的数据集,因此进行类似操作需要扫描,如果是直接相等的,则还有其他选项,如二进制搜索等。如果需要类似的功能-让数据库引擎来做,因为它适合它。。。不,你错了。他在很多方面都付出了代价,值得作为编辑添加。我决定使用你的方法,使用字典。我决定使用字典,这样我就可以轻松地搜索外部字符串键(国家代码)和内部字符串键(城市名称)的精确匹配。如果那些检查
    
    var cityCache = new Dictionary<string, Dictionary<string, int>>();
    var countryCode = "";
    var cityCode = "";
    var id = x;
    
    public static IsCityValid(City c)
    {
         return
             cityCache.ContainsKey(c.CountryCode) &&
             cityCache[c.CountryCode].ContainsKey(c.CityCode) &&
             cityCache[c.CountryCode][c.CityCode] == c.Id;  
    }