Snowung
Snowung

Reputation: 115

Remove duplicate values from hashtables

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

Answers (2)

mklement0
mklement0

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

WayneA
WayneA

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

Related Questions