繁体   English   中英

哈希由两个值组成的哈希元素中的查找元素

[英]Lookup elements in Hash where the key is composed of two values

我必须从数据库中检索以下结构:

    User ID
    User Name
    First Name
    Last Name
    Employee Number

这些字段我会将它们存储在内存中以便快速访问,换句话说就是缓存。 我们正在谈论平均30万条记录。

我的问题是,我必须创建一个用于快速查询的结构,有时按用户名,有时按雇员编号。 永远不要通过用户ID,只能通过前面提到的两个字段。

在词典中,我受制于“一键通”原则,所以...

-是否有一种方法可以创建将用户名和员工编号结合在一起以在词典中使用的密钥?

这里的问题是,有时我会获得用户指定的用户名以进行查找,有时我会获得员工编号,但永远不会同时使用。

因此,假设该密钥说MyKey(“ user-name”,“”)和MyKey(“”,“ employee-number”)应该从映射中检索相同的注册表。

我想避免在内存中创建两个词典,一个通过用户名搜索,另一个通过员工编号搜索?

一种替代方法是将来自数据库的结果存储在一个大列表中,然后使用Linq查询。 但是,这将是对O(n)的搜索,我们在这里讨论性能。

您有以下选择:

  1. 两本字典
  2. 多字典(从未使用过,但看起来非常有用)
  3. 直接访问数据库

选择可能取决于在典型情况下测试每个解决方案。 需要实验的努力。

所以我解决了创建带有Type和Value的Key对象的问题。

/// <summary>
/// Represents a composite key for cached objects
/// </summary>
public class MultiKey
{
    /// <summary>
    /// The type of key
    /// </summary>
    public enum Type
    {
        /// <summary>
        /// The key represents a User Name
        /// </summary>
        UserName,

        /// <summary>
        /// The key represents an Employee Number
        /// </summary>
        EmployeeNumber
    }

    /// <summary>
    /// Gets or sets the Type of the Key.
    /// </summary>
    public Type KeyType { get; set; }

    /// <summary>
    /// Gets or sets the value of the Key
    /// </summary>
    public string Key { get; set; }

    /// <summary>
    /// Compare based on hash code
    /// </summary>
    /// <param name="obj">the object to compare against</param>
    /// <returns>true if both objects are equals, false otherwise</returns>
    public override bool Equals(object obj)
    {
        if (obj is FormCacheKey)
        {
            return (obj as FormCacheKey).GetHashCode() == this.GetHashCode();
        }

        return false;
    }

    /// <summary>
    /// Compares based on hash code
    /// </summary>
    /// <param name="p1">left side of the operator</param>
    /// <param name="p2">right side of the operator</param>
    /// <returns>true if both items are equal, false otherwise</returns>
    public static bool operator ==(FormCacheKey p1, FormCacheKey p2)
    {
        if ((object)p1 == null && (object)p2 == null)
        {
            return true;
        }
        if ((object)p1 == null || (object)p2 == null)
        {
            return false;
        }
        return p1.Equals(p2);
    }

    /// <summary>
    /// Compares based on hash code
    /// </summary>
    /// <param name="p1">left side of the operator</param>
    /// <param name="p2">right side of the operator</param>
    /// <returns>true if both items are different, false otherwise</returns>
    public static bool operator !=(FormCacheKey p1, FormCacheKey p2)
    {
        return !(p1 == p2);
    }

    /// <summary>
    /// Returns a hash key code that identifies this object
    /// </summary>
    /// <returns>The hash code.</returns>
    public override int GetHashCode()
    {
        const int CoPrimeNumber = 37;
        var finalHashCode = 17;

        finalHashCode = (finalHashCode * CoPrimeNumber) + this.KeyType.GetHashCode();
        finalHashCode = (finalHashCode * CoPrimeNumber) + this.Key.GetHashCode();

        return finalHashCode;
    }
}

之后,我创建了一个字典

var cache = new Dictionary<MultiKey, User>();

最后,我将自己的键和值添加到字典中,如下所示:

foreach (var user in users)
{
    var userNameKey = new MultiKey { KeyType = MultiKey.Type.UserName, Key = user.UserName };
    cache.Add(userNameKey, user);
    var employeeNumberKey = new MultiKey { KeyType = MultiKey.Type.EmployeeNumber, Key = user.EmployeeNumber };
    cache.Add(employeeNumberKey, user);
}

性能说明与同事交谈时,他捍卫了两个哈希表技术,而不是我与MultiKey一起使用的方法。 他争辩说,与带有复杂键的单个缓存相比,在带有两个长叉哈希的字符串键进行搜索(访问)期间的性能“更快”或“更高效”。 他的论点是,当缓存更大/更复杂时,冲突往往会更多。 我想听听您的意见。 最后,我使用了这种方法,并且有效。

为了访问cahe中的项目,有必要提供MultiKey对象或重新创建它的方法。 从这个意义上讲,我创建了以下辅助方法

private T GetFromCache<T>(CacheKey.Type type, string key)
{
    var cKey = new MultiKey { KeyType = type, Key = key };
    T item;
    cache.TryGetValue(cKey, out item);

    return item;
}

我这样使用它:

public User GetUserByUserName(string userName)
{
    return this.GetFromDictionary<User>(MultiKey.Type.UserName, userName);
}

public User GetIndividualByEmployeeNumber(string employeeNumber)
{
    return this.GetFromDictionary<User>(MultiKey.Type.EmployeeNumber, employeeNumber);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM