1

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?

7
  • I tried two loops through this array but it didnt work Commented May 11, 2021 at 12:17
  • $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'? Commented May 11, 2021 at 12:19
  • @MathiasR.Jessen Yeah exactly. Its just an normal Array Commented May 11, 2021 at 12:20
  • And is casing important? Is A and a considered duplicates, or two distinct strings? Commented May 11, 2021 at 12:21
  • I just want to change the duplicate within an array for example by inserting a string Commented May 11, 2021 at 12:21

2 Answers 2

3

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
Sign up to request clarification or add additional context in comments.

Comments

3

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" })

2 Comments

I'm afraid I've packed away all my golf clothes for the season xD
@MathiasR.Jessen :) Yes, I know such solutions aren't for everyone, but I hope at least some readers find them helpful, especially those familiar with awk.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.