首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么字典没有AddRange?

为什么字典没有AddRange?
EN

Stack Overflow用户
提问于 2011-05-19 04:28:07
回答 11查看 93.7K关注 0票数 136

标题已经够基础了,为什么我不能:

代码语言:javascript
复制
Dictionary<string, string> dic = new Dictionary<string, string>();
dic.AddRange(MethodThatReturnAnotherDic());
EN

回答 11

Stack Overflow用户

回答已采纳

发布于 2011-05-19 04:29:58

对原始问题的评论很好地总结了这一点:

,因为从来没有人设计、指定、实现、测试、记录和发布该功能。- @Gabe Moothart

至于为什么呢?嗯,可能是因为合并字典的行为不能以一种符合框架指导方针的方式进行推理。

AddRange不存在,因为范围对于关联容器没有任何意义,因为数据范围允许重复条目。例如,如果你有一个IEnumerable<KeyValuePair<K,T>>,那么这个集合就不能防止重复的条目。

添加一组键-值对,甚至合并两个字典的行为都很简单。然而,如何处理多个重复条目的行为却并非如此。

在处理重复项时,该方法的行为应该是什么?

我能想到的解决方案至少有三种:

对于作为重复项的第一个条目,

  1. 将引发异常,该异常包含所有重复的entries
  2. Ignore

当抛出异常时,原始字典的状态应该是什么?

Add几乎总是作为原子操作实现:它成功并更新集合的状态,或者失败,而集合的状态保持不变。由于AddRange可能会由于重复错误而失败,因此保持其行为与Add一致的方法也是通过在任何重复项上抛出异常来使其原子化,并使原始字典的状态保持不变。

作为API使用者,必须迭代地删除重复的元素将是单调乏味的,这意味着AddRange应该抛出一个包含所有重复值的异常。

然后,选择归结为:

对于所有重复项,

  1. 将抛出异常,保留原始字典alone.
  2. Ignore重复项并继续。

有支持这两种用例的论据。为此,您是否向签名添加了IgnoreDuplicates标志?

IgnoreDuplicates标志(当设置为true时)也将提供显著的速度,因为底层实现将绕过重复检查的代码。

所以现在,您有了一个标志,它允许AddRange支持这两种情况,但有一个未记录的副作用(这是框架设计者非常努力避免的)。

摘要

由于在处理重复项时没有明确、一致和预期的行为,因此更容易不一起处理它们,也不提供一开始就提供的方法。

如果您发现自己必须不断地合并字典,那么您当然可以编写自己的扩展方法来合并字典,这将以适用于您的应用程序的方式运行。

票数 84
EN

Stack Overflow用户

发布于 2015-03-09 20:38:05

我有一些解决方案:

代码语言:javascript
复制
Dictionary<string, string> mainDic = new Dictionary<string, string>() { 
    { "Key1", "Value1" },
    { "Key2", "Value2.1" },
};
Dictionary<string, string> additionalDic= new Dictionary<string, string>() { 
    { "Key2", "Value2.2" },
    { "Key3", "Value3" },
};
mainDic.AddRangeOverride(additionalDic); // Overrides all existing keys
// or
mainDic.AddRangeNewOnly(additionalDic); // Adds new keys only
// or
mainDic.AddRange(additionalDic); // Throws an error if keys already exist
// or
if (!mainDic.ContainsKeys(additionalDic.Keys)) // Checks if keys don't exist
{
    mainDic.AddRange(additionalDic);
}

..。

代码语言:javascript
复制
namespace MyProject.Helper
{
  public static class CollectionHelper
  {
    public static void AddRangeOverride<TKey, TValue>(this IDictionary<TKey, TValue> dic, IDictionary<TKey, TValue> dicToAdd)
    {
        dicToAdd.ForEach(x => dic[x.Key] = x.Value);
    }

    public static void AddRangeNewOnly<TKey, TValue>(this IDictionary<TKey, TValue> dic, IDictionary<TKey, TValue> dicToAdd)
    {
        dicToAdd.ForEach(x => { if (!dic.ContainsKey(x.Key)) dic.Add(x.Key, x.Value); });
    }

    public static void AddRange<TKey, TValue>(this IDictionary<TKey, TValue> dic, IDictionary<TKey, TValue> dicToAdd)
    {
        dicToAdd.ForEach(x => dic.Add(x.Key, x.Value));
    }

    public static bool ContainsKeys<TKey, TValue>(this IDictionary<TKey, TValue> dic, IEnumerable<TKey> keys)
    {
        bool result = false;
        keys.ForEachOrBreak((x) => { result = dic.ContainsKey(x); return result; });
        return result;
    }

    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
        foreach (var item in source)
            action(item);
    }

    public static void ForEachOrBreak<T>(this IEnumerable<T> source, Func<T, bool> func)
    {
        foreach (var item in source)
        {
            bool result = func(item);
            if (result) break;
        }
    }
  }
}

玩得开心。

票数 47
EN

Stack Overflow用户

发布于 2016-06-29 00:37:31

如果有人像我一样遇到这个问题-可以通过使用IEnumerable扩展方法来实现"AddRange“:

代码语言:javascript
复制
var combined =
    dict1.Union(dict2)
        .GroupBy(kvp => kvp.Key)
        .Select(grp => grp.First())
        .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

组合字典的主要技巧是处理重复的键。在上面的代码中,它是部分.Select(grp => grp.First())。在这种情况下,它只是从复制组中获取第一个元素,但如果需要,您可以在那里实现更复杂的逻辑。

票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6050633

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档