如果键不存在,则字典返回默认值[重复]

Posted

技术标签:

【中文标题】如果键不存在,则字典返回默认值[重复]【英文标题】:Dictionary returning a default value if the key does not exist [duplicate] 【发布时间】:2011-02-05 18:52:21 【问题描述】:

我发现自己现在在我的代码中经常使用当前模式

var dictionary = new Dictionary<type, IList<othertype>>();
// Add stuff to dictionary

var somethingElse = dictionary.ContainsKey(key) ? dictionary[key] : new List<othertype>();
// Do work with the somethingelse variable

有时

var dictionary = new Dictionary<type, IList<othertype>>();
// Add stuff to dictionary

IList<othertype> somethingElse;
if(!dictionary.TryGetValue(key, out somethingElse) 
    somethingElse = new List<othertype>();

这两种方式都感觉很迂回。我真正想要的是像

dictionary.GetValueOrDefault(key)

现在,我可以为字典类编写一个扩展方法来为我做这件事,但我想我可能会遗漏一些已经存在的东西。那么,有没有一种方法可以在不为字典编写扩展方法的情况下以一种更“容易上手”的方式做到这一点?

【问题讨论】:

不确定为什么以下所有答案都如此复杂。只需使用合并运算符:string valFromDict = someDict["someKey"] ?? "someDefaultVal"; @DylanHunt 但这对值类型不起作用。 ;) 另请注意,使用[] 运算符还可能产生不希望的副作用,即在字典中添加不存在的值。 【参考方案1】:

TryGetValue 已经将类型的默认值分配给字典,因此您可以使用:

dictionary.TryGetValue(key, out value);

并忽略返回值。然而,真正只返回default(TValue),而不是一些自定义默认值(更有用的是,执行委托的结果)。没有什么比框架更强大的了。我会建议两种扩展方法:

public static TValue GetValueOrDefault<TKey, TValue>(
    this IDictionary<TKey, TValue> dictionary,
    TKey key,
    TValue defaultValue)

    return dictionary.TryGetValue(key, out var value) ? value : defaultValue;


public static TValue GetValueOrDefault<TKey, TValue>(
    this IDictionary<TKey, TValue> dictionary,
    TKey key,
    Func<TValue> defaultValueProvider)

    return dictionary.TryGetValue(key, out var value) ? value : defaultValueProvider();

(当然,您可能希望进行参数检查:)

【讨论】:

@ProfK:无论如何,您都可以将密钥与null 进行比较;当 TKey 是不可为空的值类型时,它总是返回 false。就我个人而言,我认为我不想这样做 - 根据我的经验,空键 几乎 总是代表一个错误。 @ProfK:是的 - 为您的特定案例更改代码是有意义的,但我不想一般建议:) 谢谢。第三个参数的默认值怎么样? TValue defaultValue = default(TValue) 鉴于 Jon 的回答,我被困在如何实际调用他的扩展方法上(以前从未这样做过),所以我偶然发现了这篇 MS 文章:msdn.microsoft.com/en-us/library/bb311042.aspx。 在以后的版本中,您可以使用 System.Collections.Generic,它提供 GetValueOrDefault(key, defaultValue)。【参考方案2】:

我确实喜欢扩展方法,但是当我需要默认值时,我不时使用一个简单的类来处理字典。

我希望这只是基本 Dictionary 类的一部分。

public class DictionaryWithDefault<TKey, TValue> : Dictionary<TKey, TValue>

  TValue _default;
  public TValue DefaultValue 
    get  return _default; 
    set  _default = value; 
  
  public DictionaryWithDefault() : base()  
  public DictionaryWithDefault(TValue defaultValue) : base() 
    _default = defaultValue;
  
  public new TValue this[TKey key]
  
    get  
      TValue t;
      return base.TryGetValue(key, out t) ? t : _default;
    
    set  base[key] = value; 
  

但要小心。通过子类化和使用new(因为override 在本机Dictionary 类型上不可用),如果DictionaryWithDefault 对象向上转换为普通Dictionary,则调用索引器将使用基本Dictionary 实现(如果丢失则抛出异常)而不是子类的实现。

【讨论】:

使用 trygetvalue 更好.. trygetvalue 不允许您指定默认值,即对于字符串值,您可能希望它返回 "" 而不是 null @roberocity 是的性能优势,请参阅:***.com/questions/9382681/… 上面的代码有一个bug。它将始终返回 0 作为默认值,因为 TryGetValue 将“t”设置为 0。更改为; T值 t; if (!TryGetValue(key, out t)) t = m_default; 返回 t; 我认为在这种情况下从Dictionary 继承是不明智的:通过使用new 关键字,您隐藏了非虚拟Item 属性。如果有人要从Dictionary 引用类型而不是DictionaryWithDefault 访问它,则将调用DictionaryItem 属性,而不是您的。【参考方案3】:

我创建了一个DefaultableDictionary 来满足您的要求!

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace DefaultableDictionary 
    public class DefaultableDictionary<TKey, TValue> : IDictionary<TKey, TValue> 
        private readonly IDictionary<TKey, TValue> dictionary;
        private readonly TValue defaultValue;

        public DefaultableDictionary(IDictionary<TKey, TValue> dictionary, TValue defaultValue) 
            this.dictionary = dictionary;
            this.defaultValue = defaultValue;
        

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() 
            return dictionary.GetEnumerator();
        

        IEnumerator IEnumerable.GetEnumerator() 
            return GetEnumerator();
        

        public void Add(KeyValuePair<TKey, TValue> item) 
            dictionary.Add(item);
        

        public void Clear() 
            dictionary.Clear();
        

        public bool Contains(KeyValuePair<TKey, TValue> item) 
            return dictionary.Contains(item);
        

        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) 
            dictionary.CopyTo(array, arrayIndex);
        

        public bool Remove(KeyValuePair<TKey, TValue> item) 
            return dictionary.Remove(item);
        

        public int Count 
            get  return dictionary.Count; 
        

        public bool IsReadOnly 
            get  return dictionary.IsReadOnly; 
        

        public bool ContainsKey(TKey key) 
            return dictionary.ContainsKey(key);
        

        public void Add(TKey key, TValue value) 
            dictionary.Add(key, value);
        

        public bool Remove(TKey key) 
            return dictionary.Remove(key);
        

        public bool TryGetValue(TKey key, out TValue value) 
            if (!dictionary.TryGetValue(key, out value)) 
                value = defaultValue;
            

            return true;
        

        public TValue this[TKey key] 
            get
            
                try
                
                    return dictionary[key];
                 catch (KeyNotFoundException) 
                    return defaultValue;
                
            

            set  dictionary[key] = value; 
        

        public ICollection<TKey> Keys 
            get  return dictionary.Keys; 
        

        public ICollection<TValue> Values 
            get
            
                var values = new List<TValue>(dictionary.Values) 
                    defaultValue
                ;
                return values;
            
        
    

    public static class DefaultableDictionaryExtensions 
        public static IDictionary<TKey, TValue> WithDefaultValue<TValue, TKey>(this IDictionary<TKey, TValue> dictionary, TValue defaultValue ) 
            return new DefaultableDictionary<TKey, TValue>(dictionary, defaultValue);
        
    

这个项目是一个 IDictionary 对象的简单装饰器和一个扩展方法,使其易于使用。

DefaultableDictionary 将允许围绕字典创建一个包装器,该包装器在尝试访问不存在的键或枚举 IDictionary 中的所有值时提供默认值。

示例:var dictionary = new Dictionary&lt;string, int&gt;().WithDefaultValue(5);

Blog post 的用法也是如此。

【讨论】:

请在您的回答中直接提供支持 github 链接的上下文,否则可能会被删除。 如果您不删除提供清晰的链接,将会很有帮助。 我将 index getter 写为:public TValue this[TKey key] get TValue value; TryGetValue(key, out value); return value; 以避免异常处理。 我喜欢您使用扩展方法来创建默认字典,而不是要求使用您的构造函数(就像我一样)。 基于异常的流控制...哎呀!这是一个严重的反模式。请更改您的索引器实现以使用TryGetValue 而不是try ... catch【参考方案4】:

不,不存在这样的东西。扩展方法是要走的路,你的名字(GetValueOrDefault)是个不错的选择。

【讨论】:

以上是关于如果键不存在,则字典返回默认值[重复]的主要内容,如果未能解决你的问题,请参考以下文章

元组常见操作

setdefault() python

Python 字典(Dictionary) setdefault()方法

Python3 字典 setdefault() 方法

JS:如果沿嵌套字典路径为空,则返回默认值[重复]

Python 字典(Dictionary)