简洁的方式做一个加等于可能不被初始化字典元素操作(Concise way to do a plus

2019-09-21 02:58发布

我在寻找一个扩展方法或其他任何建议,可以帮助我使这个代码尽可能简明。

foreach( Layer lyr in this.ProgramLayers )
  foreach( UWBCEvent evt in this.BcEvents.IncludedEvents )
    EventGroupLayerLosses[new EventGroupIDLayerTuple(evt.EventGroupID, lyr)] += 
       GetEL(evt.AsIfs, lyr.LimitInMillions, lyr.AttachmentInMillions);

上面的代码有一个相当明确的目的,我在瓢泼大雨值到组,复合键。 但是,此代码将失败,因为字典最初是空的和+ =运算符不知道要开始桶送行0。

我能想出的最好的是这样的:

public V AddOrSet<K, V>(this Dictionary<K, V> dict, K key, V value)
{
    if( dict.ContainsKey(key) )
        dict[key] += value;
    else
        dict[key] = value;
}

但当然,即使这样,也不能编译,因为没有办法来限制V的类型,使得运营商+=存在。

规则

  • 只有一个迭代通过双for循环。 通过前一次初始化字典,0值不允许循环。
  • 辅助方法,或扩展方法都可以使用,但我想内环成为一个衬垫。
  • 像通用和可重用尽可能使我不需要创建不同类型(小数,整数等)类似的桶装一堆相同的功能。

作为参考 - 别处在类中的键定义为实际的元组(只是与命名的参数),这就是为什么它可以被用来作为字典键:

private Dictionary<EventGroupIDLayerTuple, Decimal> _EventGroupLayerLosses;
public class EventGroupIDLayerTuple : Tuple<Int32, Layer>
{
    public EventGroupIDLayerTuple(Int32 EventGroupID, Layer Layer) : base(EventGroupID, Layer) { }
    public Int32 EventGroupID { get { return this.Item1; } }
    public Layer Layer { get { return this.Item2; } }
}

由于乔恩斯基特传递lambda函数作为第三个参数来我的扩展方法的想法。 没有必要甚至将其限制在+ =操作了。 这是通用足够的任何操作都可以通过设置新的值,如果值已经存在。

//Sets dictionary value using the provided value. If a value already exists, 
//uses the lambda function provided to compute the new value.
public static void UpdateOrSet<K, V>(this Dictionary<K, V> dict, K key, V value, Func<V, V, V> operation)
{
    V currentValue;
    if( dict.TryGetValue(key, out currentValue) )
        dict[key] = operation(currentValue, value);
    else
        dict[key] = value;
}

例子:

mySums.UpdateOrSet("Bucket1", 12, (x, y) => x + y);
myStrs.UpdateOrSet("Animals", "Dog", (x, y) => x + ", " + y);
myLists.UpdateOrSet("Animals", (List<T>) Dogs, (x, y) => x.AddRange(y));

无尽的乐趣!

Answer 1:

首先,我建议不要做的一切,你可以使尽可能短的可读性的潜在成本的东西。 例如,我想补充牙套周围foreach机构,如果一个更具可读性的解决方案结束了两行,而不是一个,我会很高兴。

其次,我要假设任何你感兴趣的类型,默认值是天然的零。

现在,你可以这样写:

public static void AddOrSet<K, V>(this Dictionary<K, V> dict,
                                  K key, V value, Func<V, V, V> addition)
{
    V existing;
    dict.TryGetValue(key, out existing);
    dict[key] = addition(existing, value);
}

然后你可以使用:

EventGroupLayerLosses.AddOrSet(new EventGroupIDLayerTuple(evt.EventGroupID, lyr),
    GetEL(evt.AsIfs, lyr.LimitInMillions, lyr.AttachmentInMillions),
    (x, y) => x + y);

使用ConcurrentDictionary会工作也很好。

此外,我会尝试,如果你能返工这是一个LINQ查询。 如果混合物我也不会感到惊讶GroupBySumToDictionary允许你以声明表示整个事情。



Answer 2:

.NET 4具有新型字典类,的ConcurrentDictionary<TKey, TValue> 。 此类具有极大的帮助AddOrUpdate表现出你正在寻找的行为方法(有一些重载)。

在ConcurrentDictionary MSDN文档



Answer 3:

我们可以只使用一个空的聚结在这里?

foreach( Layer lyr in this.ProgramLayers )
   foreach( UWBCEvent evt in this.BcEvents.IncludedEvents )
    EventGroupLayerLosses[new EventGroupIDLayerTuple(evt.EventGroupID, lyr)] = (EventGroupLayerLosses[new EventGroupIDLayerTuple(evt.EventGroupID, lyr)] ?? 0) + 
   GetEL(evt.AsIfs, lyr.LimitInMillions, lyr.AttachmentInMillions);


Answer 4:

你可以尝试这样的事情。

private void AddOrUpdate<K, V>(this Dictionary<K, V> dict, K key, Func<V> newValue, Func<V, V> updateValue) 
{ 
    V value;

    if( !dict.TryGetValue(key, out value) ) 
        value = newValue();
    else 
        value = updateValue(value); 

    dict[key] = value; 
}


文章来源: Concise way to do a plus equals operation on a Dictionary element that might not be initialized