构建哈希图的哈希图 [英] Building a Hashmap of Hashmaps

查看:27
本文介绍了构建哈希图的哈希图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不经常问问题(大多数时候,问题可以通过一些研究来解决,对吗?)但我只是想听听你的意见,因为可能有更好的(更有效的)方法。

让我们看看,下面的代码工作得很好,它达到了它的目的。代码的结果是哈希图的哈希图,我需要它作为另一项工作的查找表。

背景:

  • $ccDb是一个由大约200k项组成的数组,属性为companyCd, costCenterNbr, costCenterShortNm, costCenterLongDescr
  • 每个属性都必须修剪(请不要我修剪我的数据库,很遗憾我做不到)。
  • costCenterNbr包含在companyCd,即每个companyCd可以有多个costCenterNbr
  • companyCd可以包含costCenterNbr的X个数。
  • costCenterNbr具有唯一值,companyCd相同。
  • costCenterShortNmcostCenterLongDescrcostCenterNbr
  • 相关

问题:

这个映射必须在每次运行我的脚本时构建,因为信息是从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运行时行为的方法有很多种,但以下是我个人的首选:

  1. 安装PSProfiler(免责声明:我是PSProfiler的维护者):
    • Install-Module PSProfiler -Scope CurrentUser
  2. 以与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
        }
    }
}
  1. 等待代码完成
  2. 查看输出:

    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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆