【问题标题】:Finding values in a Dictionary<class1, class2> by a key's property通过键的属性在 Dictionary<class1, class2> 中查找值
【发布时间】:2015-09-04 07:00:46
【问题描述】:

我有一本字典:

private Dictionary<MetaInfoValueGroupTag, List<object>> checkedMetainfoValues;

如您所见,Key 类是MetaInfoValueGroupTag

private class MetaInfoValueGroupTag
{
    private string metainfo;
    //...

    public string MetaInfo
    {
        get { return metainfo; }
        set { metainfo = value; }
    }
    //...
}

我需要使用字符串对象获取Value。所以,我需要根据string来检查一个key是否存在。

string 值表示MetaInfoValueGroupTag 字典键对象的Metainfo property string 内容。

List<object> values = null;
this.checkedMetainfoValues.TryGetValue("metainfo_sample", out values);

我不想写:

List<object> values = null;
this.checkedMetainfoValues.TryGetValue(new MetaInfoValueGroupTag("metainfo_sample"), 
                                       out values);

我想避免必须创建一个新的转储key 对象来获取它的值。

我发现一定可以实现IComparer 或使用AnonymousComparer

【问题讨论】:

  • "为了获取它的值" - 如果值在语义上属于字符串,而不是MetaInfoValueGroupTags,为什么不通过string 键入字典?
  • 我需要将一些额外信息与每组值关联起来。
  • 你不能使用 Tuple> 作为值吗?所以你将使用 Dictionary>>.
  • 我认为它在乎什么......难道我的方法无法解决吗?
  • 最好不要使用key来保存信息。使用元组作为@piotrwest 的建议或创建一个额外的类来包装你的MetaInfoValueGroupTagsList&lt;object&gt;

标签: c# dictionary


【解决方案1】:

字典不是这样工作的。它为其元素的键构建哈希表并使用它进行快速搜索。

它使用IEqualityComparer&lt;T&gt; 来确定键是否相等,但您不能使用它与MetaInfoValueGroupTag 以外的其他类型进行比较。

但是,您可以使用 LINQ 扩展方法并使用 Dictionary 是IEnumerable 的事实。这意味着您可以逐个元素地枚举它并找到您需要的东西。在这里,您可以使用自定义比较器或仅使用 lambda 谓词。

为了使用扩展方法,您需要为它们添加 using:

using System.Linq;

之后,您可以在字典中使用以下方法来查找单个元素:

var searchedElement = checkedMetainfoValues.SingleOrDefault(x=>x.Key.MetaInfo == "metainfo_sample");

但请记住,它会扼杀快速获取元素的任何字典好处。它会简单地一一检查所有元素,直到提供的条件满足或到达字典的末尾。

最后最好修改您的字典以使用string 作为键,或者,如果不可能,只需创建MetaInfoValueGroupTag 对象并将其用作键。

但请注意,这取决于MetaInfoValueGroupTag 的散列算法。哈希值可能不仅取决于 MetaInfo 值,因此 new MetaInfoValueGroupTag("metainfo_sample") 可能不适合您的搜索。

阅读更多:https://msdn.microsoft.com/en-us/library/xfhwa508(v=VS.110).aspx

【讨论】:

    【解决方案2】:

    您可以像这样获取整个键/值对:

    var entry = checkedMetainfoValues.Where(x => x1.Key.MetaInfo == "metainfo_sample").Single();
    

    【讨论】:

      【解决方案3】:

      我猜字符串值是唯一的,否则你的字符串访问将不起作用。我建议把key改成string。

      private Dictionary<string, List<object>> checkedMetainfoValues;
      
      // access by meta info:
      MetaInfoValueGroupTag metaInfoGroupTag;
      var value = checkedMetaInfoValues[metaInfoGroupTag.MetaInfo]
      
      // access by string:
      string metaInfo;
      var value = checkedMetaInfoValues[metaInfo]
      

      【讨论】:

        【解决方案4】:

        如果你特别想要那个语法:

        List<object> values = null;
        this.checkedMetainfoValues.TryGetValue("metainfo_sample", out values);
        

        你可以创建自己的字典,继承自普通字典,如下:

        private class MyStrangeDictionary : Dictionary<MetaInfoValueGroupTag, List<object>>
        {
            public MyStrangeDictionary() : base(MetaInfoValueGroupTag.MetainfoComparer)
            {
            }
        
            public List<object> this[string key]
            {
                get
                {
                    return this[new MetaInfoValueGroupTag {MetaInfo = key}];
                }
                //set
                //{
                //    Add(new MetaInfoValueGroupTag { MetaInfo = key }, value);
                //} 
            }
        
            public bool TryGetValue(string key, out List<object> value)
            {
                if (ContainsKey(new MetaInfoValueGroupTag {MetaInfo = key}))
                {
                    value = this[key];
                    return true;
                }
                value = default(List<object>);
                return false;
            }
        }
        

        用法如下:

        _checkedMetainfoValues = new MyStrangeDictionary();
        
        _checkedMetainfoValues.Add(new MetaInfoValueGroupTag { MetaInfo = "f"}, new List<object> { "first"});
        _checkedMetainfoValues.Add(new MetaInfoValueGroupTag { MetaInfo = "s"}, new List<object> { "second", "2"});
        
        var test = _checkedMetainfoValues["f"];
        foreach (var t in test)
        {
            Console.WriteLine(t);
        }
        
        List<object> test1;
        _checkedMetainfoValues.TryGetValue("s", out test1);
        foreach (var t in test1)
        {
            Console.WriteLine(t);
        }
        

        编辑:

        为了完整起见,这里是你的类和比较器:

        private class MetaInfoValueGroupTag
        {
            private sealed class MetainfoEqualityComparer : IEqualityComparer<MetaInfoValueGroupTag>
            {
                public bool Equals(MetaInfoValueGroupTag x, MetaInfoValueGroupTag y)
                {
                    if (ReferenceEquals(x, y)) return true;
                    if (ReferenceEquals(x, null)) return false;
                    if (ReferenceEquals(y, null)) return false;
                    if (x.GetType() != y.GetType()) return false;
                    return string.Equals(x.metainfo, y.metainfo);
                }
        
                public int GetHashCode(MetaInfoValueGroupTag obj)
                {
                    return (obj.metainfo != null ? obj.metainfo.GetHashCode() : 0);
                }
            }
        
            private static readonly IEqualityComparer<MetaInfoValueGroupTag> MetainfoComparerInstance = new MetainfoEqualityComparer();
        
            public static IEqualityComparer<MetaInfoValueGroupTag> MetainfoComparer
            {
                get { return MetainfoComparerInstance; }
            }
        
            private string metainfo;
            //...
        
            public string MetaInfo
            {
                get { return metainfo; }
                set { metainfo = value; }
            }
            //...
        }
        

        【讨论】:

        • 您建议他制作一个包装器来做他试图避免的事情。问题中指出,他想避免仅将对象用作键来创建对象。
        • 我们不知道他是出于语法原因(也许他想在库中公开该 API)还是出于性能原因而避免创建对象。在第一种情况下,这种方法是好的,恕我直言。
        • 我认为“dump key object”暗示了这一点。但是,当然,我可能误解了这一点。仍然将一种类型定义为键并实际使用另一种类型是不好的。
        猜你喜欢
        • 1970-01-01
        • 2017-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多