查找和查找:键和值字典;查找

本文关键字:查找 字典 键和值 | 更新日期: 2023-09-27 18:02:36

我需要一个更健壮的类似字典的结构来获得:

  • 值通过提供键(默认字典行为);
  • 键通过提供一个值(不是那么琐碎)。

同时,我想扩展这个类字典结构的功能,以便一个键可以与多个值相关联。

通过这次讨论,这个答案和另一个答案提供了实现它的工具。我决定从BiDictionary中删除"按索引访问"(Jon Skeet的回答),因为歧义会比我希望的更频繁地发生(例如,在将字符串映射到字符串时)。我想到的类似字典的"结构"是:

using System.Collections.Generic;
public interface IBiLookup<TLeft, TRight>
{
    IDictionary<TLeft, ICollection<TRight>> LeftToRight { get; }
    IDictionary<TRight, ICollection<TLeft>> RightToLeft { get; }
    bool TryGetByLeft(TLeft left, out ICollection<TRight> rights);
    bool TryGetByRight(TRight right, out ICollection<TLeft> lefts);
    void Add(TLeft left, TRight right);
}
public class BiLookup<TLeft, TRight> : IBiLookup<TLeft, TRight>
{
    public IDictionary<TLeft, ICollection<TRight>> LeftToRight
    {
        get { return this.leftToRight; }
    }
    public IDictionary<TRight, ICollection<TLeft>> RightToLeft
    {
        get { return this.rightToLeft; }
    }
    public bool TryGetByLeft(TLeft left, out ICollection<TRight> rights)
    {
        return LeftToRight.TryGetValue(left, out rights);
    }
    public bool TryGetByRight(TRight right, out ICollection<TLeft> lefts)
    {
        return RightToLeft.TryGetValue(right, out lefts);
    }
    public void Add(TLeft left, TRight right)
    {
        AddLeftToRight(left, right);
        AddRightToLeft(right, left);
    }
    private void AddLeftToRight(TLeft left, TRight right)
    {
        ICollection<TRight> rights;
        // 1) Is there an entry associated with the "left" value?
        // 2) If so, is the "right" value already associated?
        if (!TryGetByLeft(left, out rights))
        {
            // Then we have to add an entry in the leftToRight dictionary.
            rights = new List<TRight> { right };                
        }
        else
        {
            // So there are entries associated with the "left" value.
            // We must verify if the "right" value itself is not there.
            if (((List<TRight>)rights).FindIndex(element => element.Equals(right)) < 0)
            {
                // We don't have that association yet.
                rights.Add(right);
            }
            else
            {
                // The value is already in the list: do nothing.
                return;
            }
        }
        LeftToRight[left] = rights;
    }
    private void AddRightToLeft(TRight right, TLeft left)
    {
        ICollection<TLeft> lefts;
        // 1) Is there an entry associated with the "right" value?
        // 2) If so, is the "left" value already associated?
        if (!TryGetByRight(right, out lefts))
        {
            // Then we have to add an entry in the leftToRight dictionary.
            lefts = new List<TLeft> { left };
        }
        else
        {
            // So there are entries associated with the "right" value.
            // We must verify if the "right" value itself is not there.
            if (((List<TLeft>)lefts).FindIndex(element => element.Equals(left)) < 0)
            {
                // We don't have that association yet.
                lefts.Add(left);
            }
            else
            {
                // The value is already in the list: do nothing.
                return;
            }
        }
        RightToLeft[right] = lefts;
    }
    #region Fields
    private IDictionary<TLeft, ICollection<TRight>> leftToRight = new Dictionary<TLeft, ICollection<TRight>>();
    private IDictionary<TRight, ICollection<TLeft>> rightToLeft = new Dictionary<TRight, ICollection<TLeft>>();
    #endregion
}

我担心将Add(…)方法拆分为两个更具体的方法是否是一个好的实现,因为billookup类将被广泛使用,性能是需要记住的事情。同样,这个线程的目的是讨论接口和类的实现是否足够好,或者可以在它们上面改进什么。

如果我将接口和"聋哑"实现都保存到类库项目中,设计是否足够好,可以重用?

查找和查找:键和值字典;查找

如果不实际使用它,就没有办法看到"设计是否足够好,可以重用"。您需要尝试以几种不同的方式使用中的代码(所有单元测试都算作一个),看看它是否有意义,并鼓励编写可读的代码。

如果您没有任何特殊的需求(性能或其他方面),只需确保代码的单元测试覆盖率良好,所有测试都通过了,并且测试涵盖了预期的使用场景。

代码说明:强制转换(即((List<TLeft>)lefts)) 看起来是不必要的。

FindIndex调用(O(number_of_items)的线性搜索)在性能敏感代码中不查找。