Reputation: 115
I am new with powershell and i need to remove duplicate values from my hashtable, eg "c"
has a duplicate 3 - "3,4,3"
and "d"
has duplicate 1 - "1,1,6,4"
.
[hashtable]$alpha = @{
"a" = "1";
"b" = "2,1,5";
"c" = "3,4,3";
"d" = "1,1,6,4";
"e" = "1,7,9,0";
}
How can I get the result?
I have already tried select-object -unique
but doesn't work.
Upvotes: 3
Views: 4333
Reputation: 438378
In order to use Select-Object -Unique
, your values must be in a collection (array), not inside a single string.
Thus, you must first split the string into an array of tokens (-split
operator), and afterwards reassemble the distinct tokens into a string (-join
operator).
foreach ($key in @($alpha.Keys)) {
$alpha.$key = ($alpha.$key -split ',' | Select-Object -Unique) -join ','
}
Note the @(...)
around $alpha.Keys
, which effectively clones the keys collection, which is necessary because you'd otherwise get an error due to trying to modify the collection while it is being enumerated, which is not supported.
In PSv3+ you could use $alpha.Keys.Clone()
instead, which is more efficient.
You could also use the pipeline with a call to the ForEach-Object
(%
) cmdlet (rather than an expression with the foreach
loop), but for in-memory data structures a foreach
loop is generally the better and faster choice.
For the sake of completeness, here's the pipeline solution (tip of the that to WayneA's answer for refining it):
@($alpha.Keys) | ForEach-Object {
$alpha[$_] = ($alpha[$_.] -split ',' | Select-Object -Unique) -join ','
}
Note that @(...)
is still needed around $alpha.Keys
, as in the foreach
statement solution.
As in the foreach
solution, this modifies the hashtable in place.
Another option is to use $alpha.GetEnumerator()
in order to force PowerShell to send the hashtable's entries one by one through the pipeline, as [System.Collections.DictionaryEntry]
instances representing key-value pairs with a .Key
and a .Value
property - by default, PowerShell outputs hashtables as a whole.
However, that necessitates creating a new hashtable, because you fundamentally cannot modify a collection being enumerated with .GetEnumerator()
(as is also implicitly used by a foreach
loop).
$newAlpha = @{} # initialize the new hash table
$alpha.GetEnumerator() | ForEach-Object {
$newAlpha[$_.Key] = ($alpha[$_.Key] -split ',' | Select-Object -Unique) -join ','
}
# $newAlpha now contains the updated entries.
Upvotes: 6
Reputation: 339
As mentioned, Those are strings, split them first and rejoin after:
$NewAlpha = $Alpha.GetEnumerator() |% { $_.value = ($_.value -split "," | select -unique) -join "," ; $_}
Note: this does not preserve the [hashtable] type. To do that you will need to employ the approach mentioned in the answer provided by mklement0
@($alpha.Keys) |% {$alpha.$_ = ($alpha.$_ -split ',' | Select-Object -Unique) -join ','}
Upvotes: 3