寻求更好的字典初始化

时间:2015-02-14 08:02:13

标签: c# python perl powershell dictionary

我最近在这里用一个PowerShell字典回答了一个问题,该字典使用“ContainsKey”来决定是否定义键值或在必要时添加键值。我做了很多 - 现在通常在C#,Python,R或PowerShell中,我厌倦了它。

是否有语言 - 甚至是库 - 可以在一行中执行以下PowerShell代码块?

  if ($sums.ContainsKey($skey))
  {
        $sums[$skey] += $sval 
  }
  else
  {
        $sums[$skey] = $sval 
  }

4 个答案:

答案 0 :(得分:5)

.NET中的

ConcurrentDictionary允许你这样做,是的:

sums.AddOrUpdate(key, value, (k, v) => v + value);

您也应该能够在PowerShell中使用它(显然也会有语法更改)。

或者,如果要在.NET中对普通Dictionary执行此操作,则可以添加扩展方法:

public static void AddOrUpdate<TKey, TValue>(
    this Dictionary<TKey, TValue> dictionary,
    TKey key,
    TValue addValue,
    Func<TKey, TValue, TValue> updateValueFactory)
{
    TValue existing;
    if (dictionary.TryGetValue(key, out existing))
    {
        dictionary[key] = updateValueFactory(key, existing);
    }
    else
    {
        dictionary[key] = addValue;
    }
}

这被编写为具有与ConcurrentDictionary方法相同的有效签名;如果您只需要Func<TValue, TValue>更新工厂,则可以相应地进行更改。

我想你可以在Python中使用辅助方法采用相同的方法 - 我不太了解Python是否可以做类似扩展方法的事情。

答案 1 :(得分:2)

在Perl中(你确实问过&#34;一种语言&#34;),你只需添加它:

my %sums;

$sums{$skey} += $sval;

如果密钥不存在,它将使用值undef创建它,在数值上等于零,然后将$sval添加到其中。如果密钥确实存在,那么操作就像您期望的那样。

答案 2 :(得分:2)

你可以在Powershell的一行中做到这一点:

$sums[$skey] += $sval

如果$ skey在$ sums中不作为键存在,它将被添加,值为$ sval。

如果确实存在,则将根据在现有值的类型上使用+ =运算符的规则更新当前值。如果它是一个数字,它将进行数学加法,如果它是一个它将连接的字符串,如果它是一个数组或集合,它将把它作为一个新元素添加。

答案 3 :(得分:1)

Python(我在这些中使用Python 3),有collections.defaultdict,其构造函数采用工厂方法,用于为缺失键创建默认值。 int()返回0,因此有利于计数。

>>> import collections
>>> sums = collections.defaultdict(int)
>>> sums['a'] += 23
>>> sums['a'] += 12
>>> sums
defaultdict(<class 'int'>, {'a': 35})

或者,如果您有可迭代的内容,则可以使用collections.Counter

>>> sums = collections.Counter(['a', 'b']) 
>>> sums['b'] += 2
>>> sums.update(['c', 'd', 'e'])
>>> sums
Counter({'b': 3, 'c': 1, 'a': 1, 'e': 1, 'd': 1})

假设你有一个要求输入的功能:

>>> def input_skey():
...    return input("Give a next skey, empty line ends> ")
...
>>> sums = collections.Counter(iter(input_skey, ''))
Give a next skey, empty line ends> foo
Give a next skey, empty line ends> bar
Give a next skey, empty line ends> baz
Give a next skey, empty line ends> baz
Give a next skey, empty line ends> bar
Give a next skey, empty line ends> foo
Give a next skey, empty line ends> baz
Give a next skey, empty line ends> 42
Give a next skey, empty line ends> 
>>> sums
Counter({'baz': 3, 'bar': 2, 'foo': 2, '42': 1})

iter(function, sentinel)生成重复调用function的迭代器,直到函数返回等于sentinel的值。)