【问题标题】:Referencing key in value when declaring a hash table in Powershell在 Powershell 中声明哈希表时引用值中的键
【发布时间】:2020-09-06 23:34:49
【问题描述】:

如果我有一个哈希表,其中在值中使用了键,例如'你好'在这个:

$ht = @{ 'hello' = 'hello world' }

是否可以在值中引用实际的键,如下所示:

$ht = @{ 'hello' = "$key world" }

现实世界的例子是一个哈希表,其中键是字段名称,值是定义如何比较两个对象之间的字段的脚本块,如下所示:

$ht = @{
  'thisField' = { Param($tp, $dp) $tp.thisField -eq $db.thisField }
  'thatField' = { Param($tp, $dp) $tp.thatField -eq $db.thatField }
}

比较通常比显示的更复杂,并且在字段之间有所不同,但每个脚本块只比较作为该块的键的字段。如果可能的话,我想做这样的事情:

$ht = @{
  'thisField' = { Param($tp, $dp) $tp.$key -eq $db.$key }
  'thatField' = { Param($tp, $dp) $tp.$key -eq $db.$key }
}

编辑:回复@Mathias R. Jessen 的问题:

真实世界的哈希表用于测试脚本。测试数据库记录是通过使用哈希表完成的,其中键是列名,脚本块定义如何根据预期值验证实际列值。比较并不总是“-eq”。

在测试表时,哈希表用于验证预期记录是否与实际记录匹配,通过根据脚本块比较每个字段,类似于:

function compare($rules, $expected, $actual)
{
  $rules.Keys | Foreach-Object {
    $key = $_            # e.g. 'thisField'
    $rule = $rules[$key] # e.g. { Param($tp, $dp) $tp.thisField -eq $db.thisField }
    if (-not (& $rule $expected $actual))
    {
      throw "Comparison failed for $key"
    }
}

使用带有脚本块的哈希表是为“数据”块中的每个表定义规则的便捷方式。效果很好,我只是想知道是否有办法避免重复列名。

【问题讨论】:

  • 不,这种关系只存在于哈希表本身。你能举例说明你想如何应用比较吗?或许可以提出替代方案
  • 这两个答案都应该适合您,归根结底是一种权衡:根据您的问题要求,一个自动将键(字段)名称合并到脚本块中,这需要在哈希表构造;另一种方法是通过将密钥作为参数添加到脚本块并将哪个脚本块使用什么密钥的逻辑移动到compare 函数中来解决这个问题。
  • @mklement0 是的,两个答案都可以。我还没有决定以哪种方式进行权衡,但是了解您和 Mathias 如何以不同的方式解决问题对我很有用,因此我可以从不同的角度看待它。非常感谢你们俩。

标签: powershell


【解决方案1】:

如果您以编程方式顺序填充哈希表,而不是使用声明性哈希表literal,则可以通过在用作价值观:

# Initialize the hashtable.
# Note: Use `$ht = [ordered] @{}` if you want to preserve the insertion order.
$ht = @{}

# Populate the key and value arrays:
# Keys:
$keys = 'thisField', 
        'thatField'
# Corresponding values (script blocks):
$values = { Param($tp, $dp) $tp.$key -eq $db.$key },
          { Param($tp, $dp) $tp.$key -eq $db.$key } # potentially different

# Populate the hashtable entry by entry.
$i = 0
$keys.ForEach({

  # Store the key in an aux. variable.
  $key = $_

  # Create the entry, calling .GetNewClosure() on the script block,
  # which captures the then-current value of $key.
  $ht[$key] = $values[$i++].GetNewClosure()

})

$ht 作为$rules 参数传递时,您的compare 函数应按预期工作。

【讨论】:

    【解决方案2】:

    由于您直接调用脚本块,您只需将$key 参数添加到比较器脚本块,然后将当前键作为参数传递:

    function compare($rules, $expected, $actual)
    {
      $rules.Keys | Foreach-Object {
        $key = $_            # e.g. 'thisField'
        $rule = $rules[$key] # e.g. { Param($tp, $dp) $tp.thisField -eq $db.thisField }
        if (-not (& $rule $expected $actual $key))
        {
          throw "Comparison failed for $key"
        }
    }
    
    $ht = @{
      'thisField' = { Param($tp, $dp, $key) $tp.$key -eq $db.$key }
      'thatField' = { Param($tp, $dp, $key) $tp.$key -eq $db.$key }
    }
    
    # ...
    
    compare $ht $expected $actual
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-22
      • 1970-01-01
      相关资源
      最近更新 更多