构建哈希图的哈希图 [英] Building a Hashmap of Hashmaps
本文介绍了构建哈希图的哈希图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我不经常问问题(大多数时候,问题可以通过一些研究来解决,对吗?)但我只是想听听你的意见,因为可能有更好的(更有效的)方法。
让我们看看,下面的代码工作得很好,它达到了它的目的。代码的结果是哈希图的哈希图,我需要它作为另一项工作的查找表。
背景:
$ccDb
是一个由大约200k项组成的数组,属性为companyCd, costCenterNbr, costCenterShortNm, costCenterLongDescr
。- 每个属性都必须修剪(请不要我修剪我的数据库,很遗憾我做不到)。
costCenterNbr
包含在companyCd
,即每个companyCd
可以有多个costCenterNbr
。companyCd
可以包含costCenterNbr
的X个数。costCenterNbr
具有唯一值,companyCd
相同。costCenterShortNm
和costCenterLongDescr
与costCenterNbr
相关
问题:
这个映射必须在每次运行我的脚本时构建,因为信息是从SQL表中获取的(它一直在变化)。构建这张地图大约需要15分钟(在一台相当好的服务器上,有2个CPU和12个核心)。问题:
您是否看到可以改进此代码以提高执行速度/效率的方法?
$ccMap=@{}
foreach($line in $ccDb)
{
$companyCd=$line.companyCd.trim()
$costCenterNbr=$line.costCenterNbr.trim()
$costCenterShortNm=$line.CostCenterShortNm.trim()
$costCenterLongDescr=$line.CostCenterLongDescr.trim()
$coceMap=@{
$costCenterNbr=@{
shortDesc=$costCenterShortNm
longDesc=$costCenterLongDescr
}
}
if($ccMap.ContainsKey($companyCd))
{
$ccMap[$companyCd]+=$coceMap
}
else
{
$ccMap.Add($companyCd,$coceMap)
}
}
很抱歉这么长的解释,但我觉得最好在前面给出最多的信息。如有任何帮助,我们不胜感激。此外,我知道PowerShell对于我正在做的事情来说是一种相当糟糕的语言,而C#可能会更高效,但它就是这样。
编辑:添加度量值以供参考。
编辑:
非常感谢@Mathias R.Jessen,以下是他的代码的测量结果。优秀的代码。
推荐答案
不要在紧密循环中使用+=
这是您最大的水槽:
$ccMap[$companyCd] += $coceMap
当您使用+
(或+=
)将一个哈希表添加到另一个哈希表时,PowerShell将创建一个全新的哈希表:
# Create two different hashtables
$A = @{ Key1 = 'Value1' }
$B = @{ Key2 = 'Value2' }
# Let's save a second reference to the first table
$remember = $A
# Now let's use += to merge the two:
$A += $B
运行$B
和$remember
时,$B
和$remember
没有变化,但$A
同时拥有两个密钥,因此必须是新的密钥。
要避免这种性能损失,请完全跳过$coceMap
的构造,并颠倒顺序(如果不存在,则先构造哈希表,然后赋值):
$ccMap=@{}
foreach($line in $ccDb)
{
$companyCd=$line.companyCd.trim()
$costCenterNbr=$line.costCenterNbr.trim()
$costCenterShortNm=$line.CostCenterShortNm.trim()
$costCenterLongDescr=$line.CostCenterLongDescr.trim()
# Create new hashtable if none exist, otherwise retrieve the existing one
if($ccMap.ContainsKey($companyCd))
{
$coceMap = $ccMap[$companyCd]
}
else
{
$coceMap = $ccMap[$companyCd] = @{}
}
$coceMap[$costCenterNbr] = @{
shortDesc=$costCenterShortNm
longDesc=$costCenterLongDescr
}
}
基准+=
这里是一个简化的例子,说明了与具有50个按键的10000个项目的区别:
$data = @(
1..10000 |Select-Object @{Name='Company';Expression={Get-Random -Maximum 50}},@{Name='CostCenter';Expression={Get-Random}}
)
@(
Measure-Command {
$map = @{}
foreach($line in $data){
$entry = @{
$line.CostCenter = @{
Value = 123
}
}
if($map.ContainsKey($line.Company)){
$map[$line.Company] += $entry
}
else {
$map[$line.Company] = $entry
}
}
}
Measure-Command {
$map = @{}
foreach($line in $data){
if($map.ContainsKey($line.Company)){
$entry = $map[$line.Company]
}
else {
$entry = $map[$line.Company] = @{}
}
$entry[$line.CostCenter] = @{
Value = 123
}
}
}
) |select TotalMilliseconds
在我的笔记本电脑上提供:
TotalMilliseconds
-----------------
306.4218
47.8164
如何识别一般情况下的时间汇聚?
分析PowerShell运行时行为的方法有很多种,但以下是我个人的首选:
- 安装
PSProfiler
(免责声明:我是PSProfiler
的维护者):Install-Module PSProfiler -Scope CurrentUser
- 以与
Measure-Command
相同的方式使用Measure-Script
:
Measure-Script {
$map = @{}
foreach($line in $data){
$entry = @{
$line.CostCenter = @{
Value = 123
}
}
if($map.ContainsKey($line.Company)){
$map[$line.Company] += $entry
}
else {
$map[$line.Company] = $entry
}
}
}
- 等待代码完成
- 查看输出:
Anonymous ScriptBlock
Count Line Time Taken Statement
----- ---- ---------- ---------
0 1 00:00.0000000 {
1 2 00:00.0000187 $map = @{}
0 3 00:00.0000000
0 4 00:00.0000000 foreach($line in $data){
10000 5 00:00.0635585 $entry = @{
0 6 00:00.0000000 $line.CostCenter = @{
0 7 00:00.0000000 Value = 123
0 8 00:00.0000000 }
0 9 00:00.0000000 }
0 10 00:00.0000000
0 11 00:00.0000000 if($map.ContainsKey($line.Company)){
9950 12 00:00.3965227 $map[$line.Company] += $entry
0 13 00:00.0000000 }
0 14 00:00.0000000 else {
50 15 00:00.0002810 $map[$line.Company] = $entry
0 16 00:00.0000000 }
0 17 00:00.0000000 }
0 18 00:00.0000000 }
注意到第12行占用的总执行时间最多-明显多于其他任何行:
9950 12 00:00.3965227 $map[$line.Company] += $entry
这篇关于构建哈希图的哈希图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文