Arrays / object keys for hashtables in powershell

When generating a hash with an array key, how can I generate a key to find the hash value. that is, without getting it from the hash counter

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

      

Using a regular array doesn't seem to work.

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

      

However, if the array object is used on creation, this seems to work.

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

      

if for example i use this to generate a hash table:

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

      

how can I generate a variable suitable for basic search?

+3


source to share


2 answers


Does the modification below help? It turns keys into strings.

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

      

Perhaps you could try.


Update to explain why you can't use arrays for hashing the way you wanted, but strings do work.

Basically, you need to know two things.

  • .NET (actually, really CLR ) has concepts of things with value semantics versus things with reference semantics . Value semantics are usually used for things with simple values ​​like strings and numbers, "xyz"

    and 167

    (arbitrary examples). Reference semantics are used for objects. Values ​​with value semantics are considered equal when their values ​​are the same . Things with reference semantics are not equal unless they are the same object (located at the same address in memory).
    Another wrinkle: things with semantic meanings can be represented by objects (this could include something called boxing and unboxing, but I'm only throwing those out there to point you to future research - that's too much to get at present) ... When objects are used to represent things with semantic values, the base class (in fact I am using a struct) is that System.ValueType

    , and comparing two elements System.ValueType

    is a special case: even if the two elements are not at the same memory address, if the two objects contain equal values , they are considered "equal".
    Take a look at the example below (comparing two ints versus two arrays) that illustrates these things. See how ints are "equal" but arrays are not.

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


  • Any .NET object (well, really, the CLR) is capable of calculating a hash code value on it, and this value is used if you use the object as a hash key. The GetHashCode () function will generate a hash code for the element. Example:$a = "xyz"; $a.GetHashCode();



Explanation of what you are facing

Put 1 and 2 above together with your question. Since an array has reference semantics, comparing two objects in an array is comparing two different objects in two different memory locations and they are not considered equal. It also means that their hash codes will not be equal .

This, using the arrays on top, echo $c.GetHashCode(); echo $d.GetHashCode();

creates two different hash codes.

However, things with value semantics, like two identical string values, will actually produce the same hash code: $e = "xyz"; $f = "xyz"; echo $e.GetHashCode(); echo $f.GetHashCode();

So, hashing with arrays got you in trouble because the hash codes generated for the keys were different (unless you were using the exact same array as you correctly observed). But hashing, say, strings gets around the problem because the hash codes are the same.

Final note

You don't need to know this to get the content of the explanation above, but one of the things the CLR will (usually) do for you is actually two values ​​of the same type be the same object (or structure) when you represent value types through objects ... So $a = "xyz"; $b = "xyz";

will actually refer to the same object, i.e. $ A is the same object as $ b - they are not just identical, they are identical. This additional information does not need to clash with the simplified information above.

+4


source


It is acceptable? Here is my hash table:

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

      

Assuming that $a.keys

gives:

Paris
Aurillac
Lyon

      

Look for $b = "Aurillac","Lyon"

as keys $a

represent a mapping between two arrays, so:



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

      

or

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

      

If you want a boolean result:

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

      

0


source







All Articles