Skip to content

Commit

Permalink
[Approaches]: Reverse String (#337)
Browse files Browse the repository at this point in the history
* [Reverse String]: Approaches

* update contents
  • Loading branch information
glaxxie authored Jan 18, 2024
1 parent 4b7207b commit 9cdd720
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Using `reverse` built-in method

```powershell
function ReverseString([string] $String) {
$charArray = $String.ToCharArray()
[Array]::Reverse($charArray)
-join $charArray
}
```

First, we turn the string into an array of chars.
Then, we pass the char array into the static method `Reverse` of the class `Array` from .NET.
Finally, we use `-join` to concatenate this char array back into one single string.

[Array.Reverse](https://learn.microsoft.com/en-us/dotnet/api/system.array.reverse) method.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function ReverseString([string] $String) {
$charArray = $String.ToCharArray()
[array]::Reverse($charArray)
-join $charArray
}
36 changes: 36 additions & 0 deletions exercises/practice/reverse-string/.approaches/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"introduction": {
"authors": ["glaxxie"],
"contributors": ["erikschierboom"]
},
"approaches": [
{
"uuid": "158c23e8-a0dc-4049-816c-770a2d4c1499",
"slug": "built-in-reverse",
"title": "built-in reverse",
"blurb": "Using the built-in reverse method of the array class.",
"authors": ["glaxxie"]
},
{
"uuid": "359c607e-ed4b-4870-b90c-f6cfd6487827",
"slug": "join-range-operator",
"title": "join range operator",
"blurb": "Reverse the string using foreach loop.",
"authors": ["glaxxie"]
},
{
"uuid": "80f36bf0-07a4-434b-9049-a29d4dfe857a",
"slug": "string-builder",
"title": "string builder",
"blurb": "Build a new string using string builder.",
"authors": ["glaxxie"]
},
{
"uuid": "9890555f-89b1-4f8f-8efa-042f4ff05c7e",
"slug": "reverse-in-place",
"title": "reverse in place",
"blurb": "Reverse the char array in place.",
"authors": ["glaxxie"]
}
]
}
84 changes: 84 additions & 0 deletions exercises/practice/reverse-string/.approaches/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Introduction

Reversing a string is quite a common problem in programming, there are many ways to achieve it in PowerShell.
We can use a built-in `reverse` method for array.
We can use `StringBuilder` object to create a new string.
Or we can manipulate the char array before returning it into the reversed string.


## General guidance

String is an immutable datatype, to reverse a string basically mean creating a new string.
The most common way to create a new string without hardcoding it is to call the `-join` operator on an array of strings/chars (without argument follow it will default to empty space).
You can also build up a string by concatenation, using `StringBuilder` or call the `ToString()` method, each have their own behavior and trade off.


## Approach: Using `range` operator and `-join`

This is a short and idiomatic solution.
Creating a char array by appling the range operator with reverse index to the string, then simply join the array.

```powershell
function ReverseString([string] $String) {
-join $String[$String.Length..0]
}
```

For more information, check the [Reverse in place approach][approach-join-range-operator].


## Approach: Using `reverse` built-in method

This is an easy way to achieve what we need with a buit-in method from .NET class [Array].

```powershell
function ReverseString([string] $String) {
$charArray = $String.ToCharArray()
[array]::Reverse($charArray)
-join $charArray
}
```

For more information, check the [`reverse` approach][approach-built-in-reverse].


## Approach: Using `StringBuilder` class

Utilizing `StringBuilder` class from .NET to build a new string by appending chars from the end of the original string.

```powershell
function ReverseString([string] $String) {
$strBuilder = [System.Text.StringBuilder]::new()
foreach ($i in ($String.Length - 1)..0) {
[void] $strBuilder.Append($String[$i])
}
$strBuilder.ToString()
}
```

For more information, check the [`StringBuilder` approach][approach-built-in-reverse].


## Approach: Reverse (swap) in place

Recognizing that reversing a string (in this case a char array), meaning we only need to swap the values of the first half to the values of the second half by the corresponding indices.

```powershell
function ReverseString([char[]] $String) {
$last = $String.Count - 1
$mid = [Math]::Ceiling($String.Count / 2)
for ($i = 0; $i -lt $mid; $i++) {
$String[$i], $String[$last - $i] = $String[$last - $i], $String[$i]
}
-join $String
}
```

For more information, check the [Reverse in place approach][approach-reverse-in-place].


## Which approach to use?

Based on preliminary benchmark run, the `range` operator with `-join` is the fastest. So consider that approach for the concise code and efficiency.


Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Using `range` operator and `-join`

```powershell
function ReverseString([string] $String) {
-join $String[$String.Length..0]
}
```

Using `range` from `$String.Length..0`, we created a range of indices from the length down to 0.
Apply the range to the string give us an array of object, in this case an array of char in reverse order of the original string.
Then we use `-join` to concatenate these character back into a single string, effectively reversing the input string.

*Note* : Technically speaking the valid range is from `($String.Length-1)..0` due to the nature of 0 based index.
However PowerShell is forgiving in these cases, and this convient feature allows simplified code, making it more concise and readable.
Whenever you need precise range of indices, make sure to use the correct range.

[Range](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_operators) operator.

[Join](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_join?view) operator.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function ReverseString([string] $String) {
-join $String[$String.Length..0]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Reverse (swap) in place

```powershell
function ReverseString([char[]] $String) {
$last = $String.Count - 1
$mid = [Math]::Ceiling($String.Count / 2)
for ($i = 0; $i -lt $mid; $i++) {
$String[$i], $String[$last - $i] = $String[$last - $i], $String[$i]
}
-join $String
}
```

This is another approach dealing with char array, so to cheat here a bit, first let cast the string into an array of char straight from parameter.
To reverse an array here, what essentially happen is that we swap the values of the first and last indices, travelling inward up to the middle index of the array.
For this method, we use a for loop to loop from 0 to the middle index, and for each step of the loop we swap values.
After the loop has completed, use `-join` operator to concatenate this char array back into one single string.

Visualize here:
```
[1,2,3,4,5] <- original array, 3 is the middle
v v
[5,2,3,4,1] <- first pass
v v
[5,4,3,2,1] <- second pass, array got reversed
```

[For](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_for) loop.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function ReverseString([char[]] $String) {
$last = $String.Count - 1
$mid = [Math]::Ceiling($String.Count / 2)
for ($i = 0; $i -lt $mid; $i++) {
$String[$i], $String[$last - $i] = $String[$last - $i], $String[$i]
}
-join $String
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Using `StringBuilder` class

```powershell
function ReverseString([string] $String) {
$strBuilder = [System.Text.StringBuilder]::new()
foreach ($i in ($String.Length - 1)..0) {
[void] $strBuilder.Append($String[$i])
}
$strBuilder.ToString()
}
```

First we create a new `StringBuilder` object from .NET.
Then we loop from the last index of the string to 0, each pass we append the current char to the `StringBuilder` object.
The append method has it own output showing some metadata, to avoid this we can ether cast [void] before the expression or pipe the output into `Out-Null` to suppress it.
When the loop is finished, we called the `ToString()` method on the `StringBuilder` object.

[StringBuilder](https://learn.microsoft.com/en-us/dotnet/api/system.text.stringbuilder) class.

[Out-Null](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/out-null) cmdlet.

[ToString](https://learn.microsoft.com/en-us/dotnet/api/system.management.automation.psobject.tostring) method.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function ReverseString([string] $String) {
$strBuilder = [System.Text.StringBuilder]::new()
foreach ($i in ($String.Length - 1)..0) {
[void] $strBuilder.Append($String[$i])
}
$strBuilder.ToString()
}

0 comments on commit 9cdd720

Please sign in to comment.