3
\$\begingroup\$

I want to join two fragments into one string with a separator, but when one of the fragments is empty I only want one of them.

I have two implementations. The first is long and slightly repetitive, but I believe it is easier to understand, since it is a more step-by-step description of the process. The second is way shorter, but less self-explanatory. It uses the Where method, and it may not be clear to everybody what the semantics of $_ are. Maybe both approaches can even be merged into an even better implementation.

Which would you recommend?

Version 1:

if ($Fragment1.Length -ne 0 -and $Fragment2.Length -ne 0) {
    $String = $Fragment2 + $Seperator + $Fragment2
} elseif ($Fragment1.Length -ne 0) {
    $String = $Fragment1
} elseif ($Fragment2.Length -ne 0) {
    $String = $Fragment2
} else {
    $String = $null
}

Version 2:

$String =
    @($Fragment2, $Fragment1).Where({$_.Length -ne 0}) -join $Seperator
\$\endgroup\$
9
  • \$\begingroup\$ As someone who doesn't use PowerShell I find the second easier to read. \$\endgroup\$ – Peilonrayz Jun 5 '20 at 15:44
  • \$\begingroup\$ OK, so you'd recommend V2? \$\endgroup\$ – schuelermine Jun 5 '20 at 15:45
  • \$\begingroup\$ Not really. I would use it. But I wouldn't recommend you to use it as you find it harder to read. \$\endgroup\$ – Peilonrayz Jun 5 '20 at 15:46
  • \$\begingroup\$ I'd like to make it clear that I'm not saying I dislike it. I am concerned about the readability of my code. I prefer version 2 myself. \$\endgroup\$ – schuelermine Jun 5 '20 at 15:49
  • \$\begingroup\$ No matter which implementation you choose, you should extract this code into a function called JoinSkipEmpty. This way it doesn't matter that much if the code is complicated or not since the name already expresses everything you need to know about the function. Oh, and please write Separator instead of Seperator. Your IDE should have told you this spelling mistake. \$\endgroup\$ – Roland Illig Jun 5 '20 at 16:20
1
\$\begingroup\$

On PowerShell v6+, I would do the following:

$String = $Fragment1, $Fragment2 |
    Where-Object { -not [System.String]::IsNullOrWhiteSpace($_) } |
    Join-String -Separator $Separator

You could use [System.String]::IsNullOrEmpty() instead of [System.String]::IsNullOrWhiteSpace(), but I find [System.String]::IsNullOrWhiteSpace() to be the desired functionality in almost all cases.

On Windows PowerShell (versions prior to v6), the Join-String command doesn't exist. There I would use:

$String = ($Fragment1, $Fragment2 |
    Where-Object { -not [System.String]::IsNullOrWhiteSpace($_) }) -join $Separator

The @().Where({ ... }) method is fairly obscure, so I tend to avoid it.

it may not be clear to everybody what the semantics of $_ are.

I'm not sure it's valuable to consider this possibility. Simply put, if your reader doesn't understand the semantics of $_, then they cannot read PowerShell. It's a ubiquitous and pervasive variable both in practice and in design.

\$\endgroup\$
0
\$\begingroup\$

here is what i meant about the -join operator being the way to go. [grin] you DO need to filter out the blank/null items, but once that is done things work neatly. i included two filters ... the basic $_ test just uses the way that "nothing" and "blank" are coerced to booleans. the other uses the builtin [string]::IsNullOrEmpty() static method.

# build some string arays to test with
$1st = 'One', 'Two', 'Three'
$2nd = 'Wun', $Null, 'Tree'
$3rd = '', 'Too', ''
$4th = 'A', 'B', ''

$Separator = '-'

# the leading comma forces the arrays to remain individual arrays instead of merging into one
foreach ($Item in (,$1st + ,$2nd + ,$3rd + ,$4th))
    {
    'Original ...'
    $Item
    'Unfiltered [will glitch with empty items] ...'
    $Item -join $Separator
    'Filtered with basic ".Where()" test ...'
    $Item.Where({$_}) -join $Separator
    'Filtered with explicit test ...'
    $Item.Where({-not [string]::IsNullOrEmpty($_)}) -join $Separator
    '=' * 30
    }

output ...

Original ...
One
Two
Three
Unfiltered [will glitch with empty items] ...
One-Two-Three
Filtered with basic ".Where()" test ...
One-Two-Three
Filtered with explicit test ...
One-Two-Three
==============================
Original ...
Wun
Tree
Unfiltered [will glitch with empty items] ...
Wun--Tree
Filtered with basic ".Where()" test ...
Wun-Tree
Filtered with explicit test ...
Wun-Tree
==============================
Original ...

Too

Unfiltered [will glitch with empty items] ...
-Too-
Filtered with basic ".Where()" test ...
Too
Filtered with explicit test ...
Too
==============================
Original ...
A
B

Unfiltered [will glitch with empty items] ...
A-B-
Filtered with basic ".Where()" test ...
A-B
Filtered with explicit test ...
A-B
==============================
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.