求更好的字典初始化
Seeking better dictionary initialization
我最近在这里用 PowerShell 字典回答了一个问题,该字典使用 "ContainsKey" 来决定是定义键值还是在必要时添加键值。我经常这样做 - 最近通常在 C#、Python、R 或 PowerShell 中,我厌倦了它。
是否有一种语言——甚至是一个库——可以在一行中执行以下 PowerShell 代码块?
if ($sums.ContainsKey($skey))
{
$sums[$skey] += $sval
}
else
{
$sums[$skey] = $sval
}
.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 的了解还不够多,无法说明您是否可以做类似扩展方法的事情。
Python(我在其中使用 Python 3),collections.defaultdict
的构造函数采用工厂方法,用于为缺少的键创建默认值。 int()
returns 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
的迭代器直到函数 returns 的值等于 sentinel
)。
在 Perl 中(你确实问过 "a language"),你只需添加它:
my %sums;
$sums{$skey} += $sval;
如果密钥不存在,它将创建一个值为 undef
的密钥,该值在数值上等于零,然后将 $sval
添加到该密钥中。如果密钥确实存在,则操作如您所料。
您可以在 Powershell 中一行完成:
$sums[$skey] += $sval
如果 $skey 不作为键存在于 $sums 中,将添加它,值为 $sval。
如果存在,则根据现有值的类型使用+=运算符的规则更新当前值。如果它是一个数字,它将进行数学加法,如果它是一个字符串,它将连接起来,如果它是一个数组或集合,它将作为一个新元素添加。
我最近在这里用 PowerShell 字典回答了一个问题,该字典使用 "ContainsKey" 来决定是定义键值还是在必要时添加键值。我经常这样做 - 最近通常在 C#、Python、R 或 PowerShell 中,我厌倦了它。
是否有一种语言——甚至是一个库——可以在一行中执行以下 PowerShell 代码块?
if ($sums.ContainsKey($skey))
{
$sums[$skey] += $sval
}
else
{
$sums[$skey] = $sval
}
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 的了解还不够多,无法说明您是否可以做类似扩展方法的事情。
Python(我在其中使用 Python 3),collections.defaultdict
的构造函数采用工厂方法,用于为缺少的键创建默认值。 int()
returns 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
的迭代器直到函数 returns 的值等于 sentinel
)。
在 Perl 中(你确实问过 "a language"),你只需添加它:
my %sums;
$sums{$skey} += $sval;
如果密钥不存在,它将创建一个值为 undef
的密钥,该值在数值上等于零,然后将 $sval
添加到该密钥中。如果密钥确实存在,则操作如您所料。
您可以在 Powershell 中一行完成:
$sums[$skey] += $sval
如果 $skey 不作为键存在于 $sums 中,将添加它,值为 $sval。
如果存在,则根据现有值的类型使用+=运算符的规则更新当前值。如果它是一个数字,它将进行数学加法,如果它是一个字符串,它将连接起来,如果它是一个数组或集合,它将作为一个新元素添加。