I have following array:
$array = 'A', 'B', 'C', 'A'
I want to identify the duplicate and add to the duplicate a string, for example, $string='Part 2'
so that I have
$array = 'A', 'B', 'C', 'A Part 2'
How do I do this in PowerShell?
Use a hashtable to keep track of strings you've already seen, then loop through all items in the array - if we've already seen the same, modify the item, otherwise leave it as is:
$array = 'A','B','C','A'
# Create hashtable to keep track of strings we've already encountered
$stringsSeen = @{}
# Now iterate over the array
$modifiedArray = $array |ForEach-Object {
if(!$stringsSeen.ContainsKey($_)){
# First encounter, add to hashtable
$stringsSeen[$_] = 1
}
else {
# We've seen it before! Time to update value and modify `$_`
$number = ++$stringsSeen[$_]
$_ += " Part $number"
}
# finally output `$_`, regardless of whether we modified it or not
$_
}
$modifiedArray now holds the new array of (partially) modified strings:
PS ~> $modifiedArray
A
B
C
A Part 2
Mathias R. Jessen's helpful answer shows an effective, readable solution.
The following solution streamlines the approach to make it more concise (though thereby potentially more obscure) and more efficient:
The .ForEach() array method is used to process the input array, as a faster alternative to the ForEach-Object cmdlet. (A foreach statement would be even faster, but is a bit more verbose).
It relies on the (non-obvious) fact that ++ applied to a non-existent hashtable entry implicitly creates the entry with value 1.
$array = 'A', 'B', 'C', 'A'
$ht = @{}
$newArray = $array.ForEach(
{ if (($count = ++$ht[$_]) -eq 1) { $_ } else { "$_ Part $count" } }
)
Note: $newArray is technically not an array, but of type [System.Collections.ObjectModel.Collection[psobject]], but that usually won't make a difference.
In PowerShell (Core) 7+ an even more concise solution is possible, using ?:, the ternary conditional operator:
$array = 'A', 'B', 'C', 'A'
$ht = @{}
$newArray = $array.ForEach({ ($count = ++$ht[$_]) -eq 1 ? $_ : "$_ Part $count" })
awk.
$array = 'A';'B';'C';'A'<--;is not an array item separator, this is just 1 assignment and 3 string literals - did you mean$array = 'A','B','C','A'?Aandaconsidered duplicates, or two distinct strings?