PowerShell中哈希表的数组/对象键

时间:2013-01-22 01:04:52

标签: .net powershell clr value-type reference-type

使用数组键创建哈希时,如何生成用于查找哈希值的键。 也就是说,没有从哈希的枚举器中获取它

$a = @{"a" = "1"
        "b" = "2"
        ("c","c1") = "3"}

使用常规数组似乎不起作用。

$k1 = @("c","c1")
$a.ContainsKey($k1)  #false

但是,如果在创建时使用数组对象,这似乎有效。

$k1 = @("c","c1")
$a = @{"a" = "1"
     "b" = "2"
 $k1 = "3"}
$a.ContainsKey($k1) #true

例如,如果我使用它来生成哈希表:

$a = Get-Eventlog system -newest 100 | Group-Object {$_.EntryType, $_.Source } -AsHashTable

如何生成一个可用于键查找的变量?

2 个答案:

答案 0 :(得分:4)

以下修改是否有帮助?它使键成为字符串。

$a = Get-Eventlog system -newest 100 | Group-Object {  
    $_.EntryType, $_.Source  
} -AsHashTable -AsString

也许你可以尝试一下。


更新以回答,解释为什么你不能按照你想要的方式使用数组进行散列,但字符串可以工作。

基本上,您需要了解两件事。

  1. .NET(实际上,CLR}具有值语义的概念与引用语义的概念。值语义通常用于具有简单值的事物,例如字符串和数字,"xyz"167(任意示例)。引用语义用于对象。 具有价值语义的东西在它们的值相同时保持相同具有引用语义的东西不相等,除非它们是完全相同的对象(位于内存中的同一地址)。
    一个额外的皱纹:具有值语义的东西可以用对象来表示(这可能涉及一些叫做装箱和拆箱的东西,但我只是把它们扔在那里指向你未来的探索 - 它太多了进入现在)。当对象用于表示具有值语义的事物时,使用的基类(我认为实际上是一个结构体)是System.ValueType,比较System.ValueType的两个项是一种特殊情况:即使这两个项不在同一个内存地址,如果两个对象包含相等的值,则它们保持“相等” 看一下下面的例子(比较两个整数和两个数组),它们说明了这些。看看int是如何“相等”而数组不是。

    $a = 167; $b = 167; echo $($a.Equals($b)); #prints True
    $c = @(167,"xyz"); $d = @(167,"xyz"); echo $($c.Equals($d)); #prints False

  2. 任何.NET(确实,CLR)对象都能够在其上计算哈希码值,并且该值是在将对象用作哈希键时使用的值。函数GetHashCode()将为项生成哈希码。示例:$a = "xyz"; $a.GetHashCode();

  3. 您遇到的问题的解释

    让我们将1和2放在一起,就你的问题而言。由于数组具有引用语义,因此比较两个数组对象是在两个不同的存储器位置比较两个不同的对象,并且它们不相等。此外,这意味着他们的哈希码不会相等

    使用上面的数组,echo $c.GetHashCode(); echo $d.GetHashCode();生成两个不同的哈希码。

    但是,具有值语义的东西,比如两个值相同的字符串,实际上会产生相同的哈希码: $e = "xyz"; $f = "xyz"; echo $e.GetHashCode(); echo $f.GetHashCode();

      

    因此,数组散列会导致问题,因为为密钥生成的哈希码是不同的(除非您使用完全相同的数组,正确观察到的内容)。   但是,通过字符串进行散列可以解决问题,因为哈希码是相同的。

    最后的注释

    你不需要知道这一点就可以得到上面解释的内容,但CLR将为你做的事情之一(通常)实际上是两个价值相同的价值类型,通过对象表示值类型时的相同对象(或结构)。因此$a = "xyz"; $b = "xyz";实际上将被用来引用同一个对象,即$ a与$ b是同一个对象 - 它们不仅仅是值相同,它们是相同的。此附加信息不需要与上述简化信息冲突。

答案 1 :(得分:0)

这可以接受吗? 这是我的哈希表:

$a = @{"Aurillac"="rouge et bleu";"Lyon"="Jaune";"Paris"="Blanc"}

假设$a.keys给出:

Paris
Aurillac
Lyon

查找$b = "Aurillac","Lyon"因为$a的键是两个数组之间的比较所以:

$a.Keys | ? {$b -contains $_}
Aurillac
Lyon

$a.Keys | ? {$b -notcontains $_}
Paris

如果你想要一个布尔结果:

($a.Keys | ? {$b -contains $_}) -eq $null