Powershell Hashtable with Initial Capacity

筅森魡賤 提交于 2019-12-23 01:16:13

问题


I was wondering how you declare a hashtable in powershell with an initial capacity. I know how large I want it to be but I have to assign the values to it in a loop.

So something like:

$hashtable = @{} (100)

回答1:


JeroenMostert makes a good point as to why you may not need to specify an initial capacity:

Be aware that pre-specifying the capacity usually doesn't win you much in terms of memory or runtime, though; it already implements generous dynamic sizing, and if your guess is off, the benefits basically evaporate.

If you do need to specify the initial capacity:

Tip of the hat to PetSerAl for his help.

Because PowerShell's hashtables are always case-insensitive with respect to key lookups, [hashtable]::new(100) does not work, unfortunately, because the default is to create a case-sensitive hashtable.

Therefore, use of a [System.Collections.Hashtable] constructor overload that allows specifying the key-equality comparison method is required, so that you can specify a culture-sensitive, case-insensitive equality comparer to match PowerShell's usual hashtable behavior[1]:

# PSv5+ syntax
$hashtable = [hashtable]::new(100, [StringComparer]::CurrentCultureIgnoreCase)

# PSv4- syntax
$hashtable = New-Object hashtable 100, ([StringComparer]::CurrentCultureIgnoreCase)

PetSerAl offers the following alternative:

$hashtable = [System.Collections.Specialized.CollectionsUtil]::CreateCaseInsensitiveHashtable(100)

Additionally, as PetSerAl points out, PowerShell caches the key-equality comparer for the current session - so an in-session change of the current culture is ignored. If you want to emulate this - questionable - behavior, PetSerAl provides the following command:

$hashtable = [hashtable]::new(100,
 [hashtable].GetProperty(
   'EqualityComparer',
   [System.Reflection.BindingFlags]'NonPublic, Instance'
 ).GetValue(@{}))

Despite the use of reflection to access a non-public property, this approach should be safe, because the targeted property's access modifier is protected, which means it has a "contract" with derived public classes and won't go away.


Note that another way to optimize a hashtable is to specify its load factor, and there are constructor overloads for specifying that factor as well.

From the docs (emphasis added):

A hash table's capacity is used to calculate the optimal number of hash table buckets based on the load factor. Capacity is automatically increased as required.

The load factor is the maximum ratio of elements to buckets. A smaller load factor means faster lookup at the cost of increased memory consumption.

When the actual load factor reaches the specified load factor, the number of buckets is automatically increased to the smallest prime number that is larger than twice the current number of buckets.


[1] Note that in many contexts PowerShell uses the invariant culture for string operations, but hashtables seem to be an exception - see this GitHub issue and this answer.
The source code reveals the use of CurrentCultureIgnoreCase in PowerShell's hashtable constructor.



来源:https://stackoverflow.com/questions/53322922/powershell-hashtable-with-initial-capacity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!