Question [Fonction] Inverser une hashtable
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
Réduire
Plus d'informations
- Messages : 6302
- Remerciements reçus 68
il y a 4 ans 4 mois - il y a 3 ans 2 mois #29863
par Laurent Dardenne
Tutoriels PowerShell
[Fonction] Inverser une hashtable a été créé par Laurent Dardenne
On peut parfois souhaiter déclarer une hashtable (clé=valeur) et tout en créant l'inverse ( valeur=clé). Par exemple :Ce qui permet de manipuler une information soit d'après son nom soit d'après sa valeur qui lui est attribuée :
L'inconvénient ici est que cette approche doit créer 2 variables, là où le C# par exemple propose des indexers .
Les classes Powershell permettent ce type de construction (voir chapitre 6.5 Indexeur) mais cela nécessite qq connaissances supplémentaires.
De plus on peut encore trouver des environnements en PS v3.0 ou v4.0 ( ce qui est mon cas et je ne peux ni charger de dll ni utiliser Add-Type).
On reprend donc les bases de Powershell, ici ETS, tout en codant simplement. Ce qui nous donne ceci:
Ce qui reste accessible je pense.
On duplique le code car on doit déclarer les types 'System.Collections.Hashtable' et 'System.Collections.Specialized.OrderedDictionary'.
La présence du second type est liée à cette astuce .
Ce qui autorise, à partir d'un hashtable en ReadOnly, la création d'un hashtable inversée et toujours en ReadOnly.
Une fois enregistré ce fichier, on l'utilise ainsi :
Les cas d'erreur étant :
Une fonction identique qui ne s'appuie pas sur ETS :
Mais j’entends une personne au fond de la salle près du radiateur qui me dit "Comment inverser une hashtable générique ?"
Exemple :
Bha, c'est un autre sujet (*).
Powershell c'est facile, mais ce n'est pas tout les jours facile...
Note: je n'ai pas de lien sur ETS (Extended Type System) à proposer car MS joue au bonneteau avec la doc de Powershell et surtout avec ce sujet.
*
Le sujet étant d'inverser n'importe quel type de hashtable générique, voir d'utiliser d'autres types avec la méthode [Linq.Enumerable]::ToDictionary
---
$h=@{
'un'=1
}
#et
$h2=@{
1='un'
}
$key='un'
$H.$key
$key='1'
$H2.$key
L'inconvénient ici est que cette approche doit créer 2 variables, là où le C# par exemple propose des indexers .
Les classes Powershell permettent ce type de construction (voir chapitre 6.5 Indexeur) mais cela nécessite qq connaissances supplémentaires.
De plus on peut encore trouver des environnements en PS v3.0 ou v4.0 ( ce qui est mon cas et je ne peux ni charger de dll ni utiliser Add-Type).
On reprend donc les bases de Powershell, ici ETS, tout en codant simplement. Ce qui nous donne ceci:
<?xml version="1.0" encoding="utf-8" ?>
<Types>
<Type>
<Name>System.Collections.Hashtable</Name>
<Members>
<ScriptMethod>
<Name>Reverse</Name>
<!-- Les types primitifs sont :
Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double et Single.
-->
<Script>
$ReverseHashtable=@{}
Foreach ($Current in $this.GetEnumerator())
{
$Key=$Current.Key
$Value=$Current.Value
if ($null -eq $Value)
{ Throw "Impossible to reverse the hashtable. The key '$Key' has a value null.The value of a key cannot be null." }
$ValueType=$Value.Gettype()
if ( ($Value -is [string]) -or $ValueType.isPrimitive)
{
try {
$ReverseHashtable.Add($Current.Value,$Key)
} catch [System.ArgumentException] {
Throw "Impossible to reverse the hashtable. Key values '$($Current.Value)' are duplicated."
}
}
else
{ Throw "Impossible to reverse the hashtable. The value '$Key' is not a scalar or a string :'$ValueType'." }
}
return ,$ReverseHashtable
</Script>
</ScriptMethod>
</Members>
</Type>
<Type>
<Name>System.Collections.Specialized.OrderedDictionary</Name>
<Members>
<ScriptMethod>
<Name>Reverse</Name>
<Script>
if ($this.IsReadOnly)
{ $ReverseHashtable=[ordered]@{} }
else
{ $ReverseHashtable=@{} }
Foreach ($Current in $this.GetEnumerator())
{
$Key=$Current.Key
$Value=$Current.Value
if ($null -eq $Value)
{ Throw "Impossible to reverse the hashtable. The key the key '$Key' has a value null.The value of a key cannot be null." }
$ValueType=$Value.Gettype()
if ( ($Value -is [string]) -or $ValueType.isPrimitive)
{
try {
$ReverseHashtable.Add($Current.Value,$Key)
} catch [System.ArgumentException] {
Throw "Impossible to reverse the hashtable. Key values '$($Current.Value)' are duplicated."
}
}
else
{ Throw "Impossible to reverse the hashtable. The value of the key '$Key' is not a scalar or a string :'$ValueType'." }
}
if ($this.IsReadOnly)
{ return ,$ReverseHashtable.AsReadOnly() }
return ,$ReverseHashtable
</Script>
</ScriptMethod>
</Members>
</Type>
</Types>
Ce qui reste accessible je pense.
On duplique le code car on doit déclarer les types 'System.Collections.Hashtable' et 'System.Collections.Specialized.OrderedDictionary'.
La présence du second type est liée à cette astuce .
Ce qui autorise, à partir d'un hashtable en ReadOnly, la création d'un hashtable inversée et toujours en ReadOnly.
Une fois enregistré ce fichier, on l'utilise ainsi :
$File='..\System.Collections.Hashtable.ps1xml'
Update-TypeData -PrependPath $File
$h=@{
'un'=1
'deux'=2
'trois'=3
}
$h.Reverse()
# Name Value
# ---- -----
# 3 trois
# 2 deux
# 1 un
Les cas d'erreur étant :
$h=@{
'un'=1
'deux'=2
'trois'=$Null
}
$h2=$h.Reverse()
#Exception lors de l'appel de «Reverse» avec «0» argument(s): «Impossible to reverse the hashtable.
#The key 'trois' has a value null.The value of a key cannot be null.»
#
#Une clé de hashtable ne peut être $null
$h=@{
'un'=1
'deux'=2
'trois'=1
}
$h2=$h.Reverse()
#Exception lors de l'appel de «Reverse» avec «0» argument(s): «Impossible to reverse the hashtable.
#Key values '1' are duplicated.»
#
#les valeurs devenant des clés on ne peut dupliquer un nom de clé
$h=@{
'un'=1
'deux'=(get-item 'G:\PS\Hashtable\Reverse.Tests.ps1') #$PSCommandPath)
'trois'=3
}
$h2=$h.Reverse()
#Exception lors de l'appel de «Reverse» avec «0» argument(s): «Impossible to reverse the hashtable.
#The value 'deux' is not a scalar or a string :'System.IO.FileInfo'.»
#
#Pour un usage sous Powershell on évite ce type de construction.
Une fonction identique qui ne s'appuie pas sur ETS :
function New-ReversedHashtable {
param($Hashtable)
if(-not ( ($Hashtable -is [System.Collections.Hashtable]) -OR ($Hashtable-is [System.Collections.Specialized.OrderedDictionary])) )
{ Throw "The argument `$Hashtable([$($Hashtable.GetType().Fullname)]) the argument must be one of the following types : [System.Collections.Hashtable], [System.Collections.Specialized.OrderedDictionary]" }
$isReadOnly=$Hashtable.IsReadOnly
if ($isReadOnly)
{ $ReverseHashtable=[ordered]@{} }
else
{ $ReverseHashtable=@{} }
Foreach ($Current in $Hashtable.GetEnumerator())
{
$Key=$Current.Key
$Value=$Current.Value
if ($null -eq $Value) #ArgumentNullException
{ Throw "Impossible to reverse the hashtable. The key '$Key' has a value null.The value of a key cannot be null." }
$ValueType=$Value.Gettype()
if ( ($Value -is [string]) -or $ValueType.isPrimitive)
{
try {
$ReverseHashtable.Add($Current.Value,$Key)
} catch [System.ArgumentException] { #ArgumentException
Throw "Impossible to reverse the hashtable. Key values '$($Current.Value)'' are duplicated."
}
}
else
{ Throw "Impossible to reverse the hashtable. The value of the key '$Key' is not a scalar or a string :'$ValueType'." }
}
if ($isReadOnly)
{ return ,$ReverseHashtable.AsReadOnly() }
return ,$ReverseHashtable
}
Mais j’entends une personne au fond de la salle près du radiateur qui me dit "Comment inverser une hashtable générique ?"
Exemple :
$h = new-object 'System.Collections.Generic.Dictionary[String,Int]'
$h.'Un'=1
$h.'Deux'=2
$h.'Trois'=3
Bha, c'est un autre sujet (*).
$KeyDelegate = [Func[[System.Collections.Generic.KeyValuePair[String,Int]],String]]{ $args[0].Key }
$ValueDelegate = [Func[[System.Collections.Generic.KeyValuePair[String,Int]],Int]]{ $args[0].Value}
$Result=[Linq.Enumerable]::ToDictionary($h, $ValueDelegate,$KeyDelegate)
$Result.GetType().Fullname
$Result
Powershell c'est facile, mais ce n'est pas tout les jours facile...
Note: je n'ai pas de lien sur ETS (Extended Type System) à proposer car MS joue au bonneteau avec la doc de Powershell et surtout avec ce sujet.
*
Le sujet étant d'inverser n'importe quel type de hashtable générique, voir d'utiliser d'autres types avec la méthode [Linq.Enumerable]::ToDictionary
---
Tutoriels PowerShell
Dernière édition: il y a 3 ans 2 mois par Laurent Dardenne. Raison: Correction du code suivant : if ( ($ValueType -isnot [string]) -and $ValueType.isPrimitive)
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
Réduire
Plus d'informations
- Messages : 6302
- Remerciements reçus 68
il y a 3 ans 9 mois #30344
par Laurent Dardenne
Tutoriels PowerShell
Réponse de Laurent Dardenne sur le sujet [Fonction] Inverser une hashtable
En attendant un tutoriel sur l'usage des génériques avec Powershell, voici une première ébauche :Le dernier résultat n'est pas du type attendu (system.collections.Generic.SortedList[Int,String]), un jeu de test Pester serait le bienvenue
Si ce sujet vous intéresse et en attendant la finalisation du tutoriel sur les génériques, vous pouvez consulter cet article : www.red-gate.com/simple-talk/dotnet/net-...nce-powershell-linq/
A suivre
function Inverse{
param(
$InputObject
)
#On manipule des informations du type
$SourceType=$InputObject.GetType()
if ($SourceType.IsGenericType -eq $false)
{ Throw 'InputObject doit être un type générique.' }
# On distingue les deux erreurs
if ($SourceType.IsGenericTypeDefinition -eq $true)
{ Throw 'InputObject doit être un type générique fermé.' }
#On cherche à savoir si $inputObject implémente l'interface générique
# IDictionary<TKey,TValue> ( qui elle même implémente System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>)
$isIDictionaryImplemented=$InputObject.GetType().GetInterfaces().Where({
if ($_.isGenericType)
{ $_.GetGenericTypeDefinition().fullname -eq 'System.Collections.Generic.IDictionary`2'}
}).Count -eq 1
# Note MsDoc :
# L'interface IDictionary<TKey,TValue> est l’interface de base pour les collections génériques de paires clé/valeur.
# Chaque élément est une paire clé/valeur stockée dans un KeyValuePair<TKey,TValue> objet.
if ($isIDictionaryImplemented -eq $false)
{ Throw 'InputObject n''est pas une collection générique de paires clé/valeur (IDictionary<TKey,TValue>).' }
#On récupère les types utilisés pour créer la 'hashtable' générique ( TODO : le type peut être différent)
$GenericArguments=$InputObject.GetType().GetGenericArguments()
#Crée un type ouvert à partir de la classe System.Collections.Generic.KeyValuePair
#Ici on sait que ce type générique à deux arguments de type; cf. 'System.Collections.Generic.IDictionary`2'
$KeyValuePairType=[Type]'System.Collections.Generic.KeyValuePair`2'
Write-debug "KeyValuePairType : $($KeyValuePairType.ToString())"
Write-debug "KeyValuePairType est un type ouvert ? $($KeyValuePairType.IsGenericTypeDefinition -eq $true)"
#Crée un type fermé (exemple: System.Collections.Generic.KeyValuePair<String,Int> ) à partir des arguments de type de $InputObject
#C'est une classe générique différente mais les types des arguments sont identiques
$DelegateInputParameterType=$KeyValuePairType.MakeGenericType($GenericArguments)
Write-debug "DelegateInputParameter : $($DelegateInputParameterType.ToString())"
Write-debug "DelegateInputParameter est un type fermé ? $($DelegateInputParameterType.IsGenericTypeDefinition -eq $false)"
#On crée les foncteurs nécessaires pour manipuler les argument de types de $InputObject
#on sait, d'après 'System.Collections.Generic.IDictionary`2', que le functor à deux arguments de type
$FunctorType=[Type]'Func`2'
#L'ordre de la liste des paramètres correspond à celui
# indiqué lors de la création de l'objet
[Type[]] $ParametersType=@($DelegateInputParameterType,$GenericArguments[0])
$KeyDelegateType=$FunctorType.MakeGenericType($ParametersType)
Write-debug "Foncteur pour KeyDelegateType : $($KeyDelegateType)"
[Type[]] $ParametersType=@($DelegateInputParameterType,$GenericArguments[1])
$ValueDelegateType=$FunctorType.MakeGenericType($ParametersType)
Write-debug "Foncteur pour ValueDelegateType : $($ValueDelegateType)"
#Cast nécessaire des scriptblocks
$KeyDelegate = { $args[0].Key } -as $KeyDelegateType
$ValueDelegate ={ $args[0].Value} -as $ValueDelegateType
#Bien que le paramètre $InputObject ne soit pas typé dans l'entête de la fonction, on manipule un PSObject
#on doit donc récupérer l'objet encapsulé via la propriété PsObject.BaseObject
#Sinon on a une erreur d'appel
#
#L'ordre des délégués est ici inversé puisque c'est l'objectif : la valeur devient la clé et inversement
$Result=[Linq.Enumerable]::ToDictionary($InputObject.PsObject.BaseObject, $ValueDelegate,$KeyDelegate)
,$Result
}
$h = new-object 'System.Collections.Generic.Dictionary[String,Int]'
$h.'Un'=1
$h.'Deux'=2
$h.'Trois'=3
$Result=Inverse $h
$Result
# Key Value
# --- -----
# 1 Un
# 2 Deux
# 3 Trois
$h2 = new-object 'System.Collections.Generic.Dictionary[Int,String]'
$h2.Add(1,'Un')
$h2.Add(2,'Deux')
$h2.Add(3,'Trois')
$Result=Inverse $h2
$Result
# Key Value
# --- -----
# Un 1
# Deux 2
# Trois 3
#Similaire à [Ordered]}
$SL = new-object 'System.Collections.Generic.SortedList[String,Int]'
$SL.Add("Un", 1)
$SL.Add("Deux", 2)
$SL.Add("Trois", 3)
$Result=Inverse $SL
$Result
Si ce sujet vous intéresse et en attendant la finalisation du tutoriel sur les génériques, vous pouvez consulter cet article : www.red-gate.com/simple-talk/dotnet/net-...nce-powershell-linq/
A suivre
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
Réduire
Plus d'informations
- Messages : 6302
- Remerciements reçus 68
il y a 3 ans 9 mois #30353
par Laurent Dardenne
Tutoriels PowerShell
Réponse de Laurent Dardenne sur le sujet [Fonction] Inverser une hashtable
Une solution au dernier point, convertir le résultat d'appel de [Linq.Enumerable]::ToDictionary dans le type d'origine en inversant ses arguments.
On peut utiliser cette mécanique de conversion .
Car si on consulte la documentation des classes génériques implémentant IDictionary<TKey,TValue>, on constate qu'elles proposent toutes un constructeur attendant un IDictionnary générique.
Pour cette partie on utilise une string contenant le nom de type :La version modifiée :
On peut utiliser cette mécanique de conversion .
Car si on consulte la documentation des classes génériques implémentant IDictionary<TKey,TValue>, on constate qu'elles proposent toutes un constructeur attendant un IDictionnary générique.
Pour cette partie on utilise une string contenant le nom de type :
$Result=[Linq.Enumerable]::ToDictionary($InputObject.PsObject.BaseObject, $ValueDelegate,$KeyDelegate)
if ("$SourceType" -notmatch '^System\.Collections\.Generic\.Dictionary\[')
{
#On récupère le 'nom court' du type : FullClassName[String,Int]
# On n'utilise pas ici le système de réflexion de dotNet.
$TargetTypeName="$SourceType"
#On inverse <TKey,TValue> pour avoir <TValue,TKey>
#Note: on suppose que TKey,TValue ne sont pas des types génériques
$TargetTypeName=$TargetTypeName -replace '^(.*?)\[(.*?),(.*)\]$','$1[$3,$2]'
Write-Debug "Tente un transtypage à la Powershell vers le type $TargetTypeName"
#Peut appeler un constructeur utilisant un dictionnaire générique en paramètre.
#Cf. https://devblogs.microsoft.com/powershell/understanding-powershells-type-conversion-magic/
$Result=$Result -as [Type]$TargetTypeName
If ($null -eq $Result)
{ Throw "Impossible to cast the type '$($Result.Gettype())' to '$TargetTypeName'." }
}
function Inverse{
param(
$InputObject
)
#On manipule des informations du type
$SourceType=$InputObject.GetType()
if ($SourceType.IsGenericType -eq $false)
{ Throw 'InputObject doit être un type générique.' }
# On distingue les deux erreurs
if ($SourceType.IsGenericTypeDefinition -eq $true)
{ Throw 'InputObject doit être un type générique fermé.' }
#On cherche à savoir si $inputObject implémente l'interface générique
# IDictionary<TKey,TValue> ( qui elle même implémente System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<TKey,TValue>>)
$isIDictionaryImplemented=$InputObject.GetType().GetInterfaces().Where({
if ($_.isGenericType)
{ $_.GetGenericTypeDefinition().fullname -eq 'System.Collections.Generic.IDictionary`2'}
}).Count -eq 1
# Note MsDoc :
# L'interface IDictionary<TKey,TValue> est l'interface de base pour les collections génériques de paires clé/valeur.
# Chaque élément est une paire clé/valeur stockée dans un KeyValuePair<TKey,TValue> objet.
if ($isIDictionaryImplemented -eq $false)
{ Throw 'InputObject n''est pas une collection générique de paires clé/valeur (IDictionary<TKey,TValue>).' }
#On récupère les types utilisés pour créer la 'hashtable' générique ( TODO : le type peut être différent)
$GenericArguments=$InputObject.GetType().GetGenericArguments()
#Crée un type ouvert à partir de la classe System.Collections.Generic.KeyValuePair
#Ici on sait que ce type générique à deux arguments de type; cf. 'System.Collections.Generic.IDictionary`2'
$KeyValuePairType=[Type]'System.Collections.Generic.KeyValuePair`2'
Write-debug "KeyValuePairType : $($KeyValuePairType.ToString())"
Write-debug "KeyValuePairType est un type ouvert ? $($KeyValuePairType.IsGenericTypeDefinition -eq $true)"
#Crée un type fermé (exemple: System.Collections.Generic.KeyValuePair<String,Int> ) à partir des arguments de type de $InputObject
#C'est une classe générique différente mais les types des arguments sont identiques
$DelegateInputParameterType=$KeyValuePairType.MakeGenericType($GenericArguments)
Write-debug "DelegateInputParameter : $($DelegateInputParameterType.ToString())"
Write-debug "DelegateInputParameter est un type fermé ? $($DelegateInputParameterType.IsGenericTypeDefinition -eq $false)"
#On crée les foncteurs nécessaires pour manipuler les argument de types de $InputObject
#on sait, d'après 'System.Collections.Generic.IDictionary`2', que le functor à deux arguments de type
$FunctorType=[Type]'Func`2'
#L'ordre de la liste des paramètres correspond à celui
# indiqué lors de la création de l'objet
[Type[]] $ParametersType=@($DelegateInputParameterType,$GenericArguments[0])
$KeyDelegateType=$FunctorType.MakeGenericType($ParametersType)
Write-debug "Foncteur pour KeyDelegateType : $($KeyDelegateType)"
[Type[]] $ParametersType=@($DelegateInputParameterType,$GenericArguments[1])
$ValueDelegateType=$FunctorType.MakeGenericType($ParametersType)
Write-debug "Foncteur pour ValueDelegateType : $($ValueDelegateType)"
#Cast nécessaire des scriptblocks
$KeyDelegate = { $args[0].Key } -as $KeyDelegateType
If ($null -eq $KeyDelegate)
{ Throw "Impossible to cast the 'Key' scriptblock to '$KeyDelegateType'."}
$ValueDelegate ={ $args[0].Value} -as $ValueDelegateType
If ($null -eq $ValueDelegate)
{ Throw "Impossible to cast the 'Value' scriptblock to '$ValueDelegate'."}
#Bien que le paramétre $InputObject ne soit pas typé dans l'entête de la fonction, on manipule un PSObject
#on doit donc récupérer l'objet encapsulé via la propriété PsObject.BaseObject
#Sinon on a une erreur d'appel
#
#L'ordre des délégués est ici inversé puisque c'est l'objectif : la valeur devient la clé et inversement
$Result=[Linq.Enumerable]::ToDictionary($InputObject.PsObject.BaseObject, $ValueDelegate,$KeyDelegate)
if ("$SourceType" -notmatch '^System\.Collections\.Generic\.Dictionary\[')
{
#On récupère le 'nom court' du type : FullClassName[String,Int]
# On n'utilise pas ici le système de réflexion de dotNet.
$TargetTypeName="$SourceType"
#On inverse <TKey,TValue> pour avoir <TValue,TKey>
#Note: on suppose que TKey,TValue ne sont pas des types génériques
# IDictionary<typeof(T), T> est impossible.
$TargetTypeName=$TargetTypeName -replace '^(.*?)\[(.*?),(.*)\]$','$1[$3,$2]'
Write-Debug "Tente un transtypage à la Powershell vers le type $TargetTypeName"
#Peut appeler un constructeur utilisant un dictionnaire génèrique en paramètre.
#Cf. https://devblogs.microsoft.com/powershell/understanding-powershells-type-conversion-magic/
$Result=$Result -as [Type]$TargetTypeName
If ($null -eq $Result)
{ Throw "Impossible to cast the type '$($Result.Gettype())' to '$TargetTypeName'." }
}
Write-Output $Result -NoEnumerate
}
$h = new-object 'System.Collections.Generic.Dictionary[String,Int]'
$h.'Un'=1
$h.'Deux'=2
$h.'Trois'=3
$Result=Inverse $h
$Result
# Key Value
# --- -----
# 1 Un
# 2 Deux
# 3 Trois
"$($Result.GetType())"
#System.Collections.Generic.Dictionary[int,string]
$h2 = new-object 'System.Collections.Generic.Dictionary[Int,String]'
$h2.Add(1,'Un')
$h2.Add(2,'Deux')
$h2.Add(3,'Trois')
$Result=Inverse $h2
$Result
# Key Value
# --- -----
# Un 1
# Deux 2
# Trois 3
"$($Result.GetType())"
#System.Collections.Generic.Dictionary[string,int]
#Similaire à [Ordered]
#ou a System.Collections.Generic.SortedDictionary<TKey,TValue>
$SL = new-object 'system.collections.Generic.SortedList[String,Int]'
$SL.Add("Un", 1)
$SL.Add("Deux", 2)
$SL.Add("Trois", 3)
$Result=Inverse $SL
$Result
"$($Result.GetType())"
#System.Collections.Generic.SortedList[int,string]
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Boelpaep
- Hors Ligne
- Nouveau membre
Réduire
Plus d'informations
- Messages : 3
- Remerciements reçus 0
il y a 3 ans 3 mois - il y a 3 ans 2 mois #31102
par Boelpaep
Réponse de Boelpaep sur le sujet [Fonction] Inverser une hashtable
renverser la key et value:
Si
le variable que vous voulez reverser sapelle $myvar:
Alors
renversera votre variable
explication:
Alternative qui donne du feedback et autonumérote les duplicates
Si
le variable que vous voulez reverser sapelle $myvar:
$myvar=@{"a"="1";"b"="2";"c"=3;"d"=$null;"e"=3;"f"="1";} #sample data
Alors
$myrev=@{};$myvar.keys|%{if($myvar[$_] -match '^[a-z0-9]+$'){$myrev[$myvar[$_]]=$_}};$myvar=$myrev
renversera votre variable
explication:
#sample data $myrev=@{}; # create temporary variable
$myvar.keys|%{
if($myvar[$_] -match '^[a-z0-9]+$'){$myrev[$myvar[$_]]=$_} #invert key<> value if value is alphanumeric otherwise throw away
};
$myvar=$myrev # copy temp var to initial variable
Alternative qui donne du feedback et autonumérote les duplicates
$mytmp=@{} # temporary variable that stores
$myrev=@{}; # create reverse destination variable
$dedup=@{}; # helper variable
# Clean values : remove non alphanumeric values + autonumber duplicate values AND put in temp variable
$myvar.keys|%{ #clean values (duplicates and no alphnumeric)
$val=[string]$myvar[$_]
if($val -match '^[a-z0-9]+$'){ #copy keyvalue pairs that are alphnumeric
$dedup[$val]=1+$dedup[$val]; # Alter value if it is a duplicate
if($dedup[$val] -gt 1) {$mytmp[$_]=$val+"_"+$dedup[$val];"Duplicate detected on key($_)/val($val), renamed value!"}
else {$mytmp[$_]=$val;}
} else {"Non Alphanumeric value detected! on key '$_', value and key will be removed"} #
}
$mytmp.keys|%{$myrev[$mytmp[$_]]=$_} #invert clean array : key<> value and store in $myrev (myreversed variable)
Dernière édition: il y a 3 ans 2 mois par Boelpaep. Raison: J'ai ajouter un if notmatch pour verifier que le value peut etre utiliser comme cléf d'un hashtable
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
Réduire
Plus d'informations
- Messages : 6302
- Remerciements reçus 68
il y a 3 ans 3 mois #31103
par Laurent Dardenne
Tutoriels PowerShell
Réponse de Laurent Dardenne sur le sujet [Fonction] Inverser une hashtable
Salut,
$env n'existe pas.
En cas de duplication de valeur, il y a une perte d'information et si une des valeurs vaut $null il y a une exception. je n'ai pas testé avec des valeurs ayant un type qui n'est pas scalaire.
Ton code fonctionne si on sait que ces 3 points ne se présenteront pas.
L'objectif état d'avoir 2 hashtables :
On peut parfois souhaiter déclarer une hashtable (clé=valeur) et tout en créant l'inverse
$env n'existe pas.
En cas de duplication de valeur, il y a une perte d'information et si une des valeurs vaut $null il y a une exception. je n'ai pas testé avec des valeurs ayant un type qui n'est pas scalaire.
Ton code fonctionne si on sait que ces 3 points ne se présenteront pas.
L'objectif état d'avoir 2 hashtables :
On peut parfois souhaiter déclarer une hashtable (clé=valeur) et tout en créant l'inverse
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Boelpaep
- Hors Ligne
- Nouveau membre
Réduire
Plus d'informations
- Messages : 3
- Remerciements reçus 0
il y a 3 ans 3 mois - il y a 3 ans 3 mois #31104
par Boelpaep
Réponse de Boelpaep sur le sujet [Fonction] Inverser une hashtable
Bonjour,
Probleme 1/3 (erreure de code reparé dans la source)
En effet $env devait etre $myvar je l'ai corriger dans mon code
Probleme 2/3 (normalle)
Pour ce qui est de valeurs duplication, se sera toujours le cas, un dictionary key doit toujours etre unique, donc les values qui existent déja peuvent seulement occupé une seule key
Probleme 3/3
resolu avec un If match pour verifié si le value est alphanumeric, tout le reste peut pas etre utilisé en tant que key
(code adaptéé dans mon post initiel)
"lobjectif cetait davoir deux hash" ils sont la, $myvar et $myrev (my reverse) il suffit de pas utiliser ma dernierre ligne code dexecution $myvar=$myrev
Probleme 1/3 (erreure de code reparé dans la source)
En effet $env devait etre $myvar je l'ai corriger dans mon code
Probleme 2/3 (normalle)
Pour ce qui est de valeurs duplication, se sera toujours le cas, un dictionary key doit toujours etre unique, donc les values qui existent déja peuvent seulement occupé une seule key
Probleme 3/3
resolu avec un If match pour verifié si le value est alphanumeric, tout le reste peut pas etre utilisé en tant que key
(code adaptéé dans mon post initiel)
"lobjectif cetait davoir deux hash" ils sont la, $myvar et $myrev (my reverse) il suffit de pas utiliser ma dernierre ligne code dexecution $myvar=$myrev
Dernière édition: il y a 3 ans 3 mois par Boelpaep.
Connexion ou Créer un compte pour participer à la conversation.
Temps de génération de la page : 0.075 secondes
- Vous êtes ici :
- Accueil
- forum
- PowerShell
- Contributions à la communauté
- [Fonction] Inverser une hashtable