Day 2/30 Days of CodeWars: JavaScript Edition
Published: 2022-06-01 20:36:01

**CodeWars challenges solved**
1) [Grasshopper - Personalized Message (8 kyu)](https://www.codewars.com/kata/5772da22b89313a4d50012f7/train/javascript)
2) [Parse nice int from char problem (8 kyu)](https://www.codewars.com/kata/557cd6882bfa3c8a9f0000c1/train/javascript)
3) [Correct the mistakes of the character recognition software (8 kyu)](https://www.codewars.com/kata/577bd026df78c19bca0002c0/train/javascript)

---

## Kata 1: Grasshopper - Personalized Message
### Instructions
Create a function that gives a personalized greeting. This function takes two parameters: `name` and `owner`.

Use conditionals to return the proper message:
- name equals owner => 'Hello boss'
- otherwise => 'Hello guest'

---

### Breaking down the problem 

<u>Parameters</u>

As mentioned in the instructions above, the function expects two parameters: `name` and `owner`.

Based on the test cases, both are expected to be (valid) strings, though in actuality they might not be.

<u>Returns</u>
The function should return one value: a string.

What string should be returned depends on whether or not the `name` and `owner` match _(see instructions above)_.

<u>Examples</u>
The following test cases are provided by CodeWars.

```
('Daniel', 'Daniel'), 'Hello boss'
('Greg', 'Daniel'), 'Hello guest'
```

_The first two values are the arguments that will be passed to the function, followed by the message that should be returned._

---

This coding challenge is fairly similar to [the third kata solved yesterday](https://dev.to/nats_tech_notes/day-130-days-of-codewars-javascript-edition-3560#:~:text=Kata%203%3A%20Keep%20up%20the%20hoop) with some minor differences. So instead of reiterating through the same solutions mentioned in that kata, I'll be providing some variations to those solutions as well as diving deeper into error handling.

---

### Solution 1: Basic implementations without error handling
_The following implementations assume that the arguments passed to the function are valid strings (like in the test cases provided by CodeWars)._ 

{% details **Variant 1: using if/else statements** %}

```javascript
function greet (name, owner) {
  if (name === owner) {
    return "Hello boss";
  } else {
    return "Hello guest";
  }
}
```

This is the easiest and probably most common implementation.

---


{% enddetails %}
---

{% details **Variant 2: using an if statement only** %}

```javascript
function greet (name, owner) {
  if (name === owner) return "Hello boss";
  return "Hello guest";
}
```

This is a similar approach to variant 1, with 2 main differences:

1) The `if statement` is written on 1 line and the `{}` after the statement's condition have been omitted. This is valid code for one-line conditional statements, though it is usually recommended to add the `{}`. It is also important to note that (most) [JavaScript linters](https://gomakethings.com/javascript-linters/) will add the `{}` when formatting code if they have been omitted.

2) There is no `else statement`. It has been replaced by another `return` outside of the `if statement`. This works because the function can only execute 1 `return` so if it does not execute the code inside the `if statement`, it will return the string specified outside of the `if statement`.

---

{% enddetails %}

{% details **Variant 3: using a conditional ternary operator** %}


```javascript
function greet (name, owner) {
  return name === owner ? "Hello boss" : "Hello guest";
}
```

---

{% enddetails %}

{% details **Variant 4: using template literal syntax** %}

```javascript
function greet (name, owner) {
  return `Hello ${name === owner ? 'boss' : 'guest'}`;
}
```

[Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) are useful to create complicated and multi-line strings that can include single and double quotes, as well as variables and expressions (like the ternary operator above). It also eliminates the need to concatenate strings using the `+` operator. 

{% enddetails %}

---

### Solution 2: Handling input that is not a string
_The implementations from solution 1 pass the test cases provided by CodeWars, but they also pass when the arguments provided are `numbers`, `null`, `undefined`, `objects` and `arrays` for examples. This is likely not behavior we would want in a real life scenario, so let's add some code to handle cases where one or both of the arguments passed are not strings._

<u>Examples</u>
The following test cases have been added by me:

```
(2, 5), 'Invalid input'
({}, []), 'Invalid input'
(null, 'undefined'), 'Invalid input'
('null', 'undefined'), 'Hello guest'
```

{% details **Variant 1: using if/else if statements** %}

```javascript
function greet (name, owner) {
  const isValidName = typeof name === "string";
  const isValidOwner = typeof owner === "string";
  const isValidArgs = isValidName && isValidOwner;

  if (!isValidArgs) return "Invalid input";
  else if (isValidArgs && name == owner) return "Hello boss";
  return "Hello guest";
}
```

_Notes_: 

1) The [typeof operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof) is used to verify that the `name` and `owner` arguments are `strings`. 

2) It is common practice to start variables storing a [Boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean) value with 'is'.

3) The 3 first lines can easily be reworked into 1 line. I just chose to split them up for this article to make it a little easier to follow along with what is going on.

4) The `if statement` uses the [logical not (!) operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_NOT) to return the string `"Invalid input"` if `isValidArgs` is false (meaning one or both of the arguments are not strings). 

---

{% enddetails %}

{% details **Variant 2: using a nested ternary operator** %}

```javascript
function greet (name, owner) {
  // variable declarations (deleted for legibility) 

  return !isValidParams 
    ? "Invalid input" 
    : isValidParams && name === owner 
      ? "Hello boss"
      : "Hello guest"
}
```

{% enddetails %}

---

### Solution 3: Handling invalid input/strings

_Besides arguments that aren't strings, there is another (edge) case that we want to consider: invalid strings such as empty strings and strings containing only white-space. Depending on the real-world context our code is implemented in, the rules on what is considered an invalid string might be less or more strict, but for the purposes of this exercise, we'll assume that both names (first, last and full) and usernames are allowed._

{% details **Test cases and solution** %}

```
('nats_tech_notes', 'nats_tech_notes'), 'Hello boss'
('@Nat_A_Number', '12345'), 'Hello guest'
('', ''), 'Invalid input'
(' ', ' '), 'Invalid input'
(3, 5), 'Invalid input'
```

The test cases above were added by me.

```javascript
function greet (name, owner) {
  const regex = /^[\S]\w/;
  const isValidName = typeof name == "string" 
                      && regex.test(name);
  const isValidOwner = typeof owner == "string"
                       && regex.test(owner);
  const isValidArgs = isValidName && isValidOwner;

  // deleted code: same code from solution 2
}
```

_Notes_: 

1) To test the validity of the string, [regular expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions) are used. 

2) The regular expression starts with the `^` [assertion](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Assertions) symbol, signifying the beginning of the string, followed by the `\S` [character class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes) to indicate no white-space. This ensures the string cannot start with or contain only white-space. It also contains the `\w` character class to verify the string contains at least 1 alphanumerical character. This combination allows for full/multiple names to be used which will contain white-space between each name.

---

{% enddetails %}

---

## Kata 2: Parse nice int from char problem
### Instructions
You ask a small girl,"How old are you?" She always says, "x years old", where x is a random number between 0 and 9.

Write a program that returns the girl's age (0-9) as an integer.

Assume the test input string is always a valid string. For example, the test input may be "1 year old" or "5 years old". The first character in the string is always a number.

---

### Breaking down the problem 

<u>Parameters</u>
The function expects 1 parameter: a string.

The instructions specify the string will always be a valid string and the first character in the string will always be the age.

<u>Returns</u>

The function should return 1 value: a number, more specifically an integer.

<u>Examples</u>

The following test cases are provided by CodeWars.

```
("4 years old"), 4
```

_The first value is the string that will be passed to the function, followed by the integer that should be returned._

---

### Solution 1: using parseInt()

```javascript
function getAge(inputString){
  return parseInt(inputString);
}
```

_Notes_: 

The [`parseInt()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) receives a string and returns an integer number if a number is present inside the string. If no number is present, it returns `NaN`. 

---

### Solution 2: using Number()

```javascript
function getAge(inputString){
  return Number(inputString[0]);
}
```

_Notes_: 

1) The [`Number()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number) can convert values that are not numbers into numbers. 

2) Just like arrays, the bracket notation can be used with strings to select a character at the specified index (`string[index]`). 

---

### Solution 3: using regex and the unary operator

```javascript
function getAge(inputString){
  const numChar = inputString.match(/\d/);
  return +numChar;

  // alternatively:
  // return +inputString.match(/\d/);
}
```

_Notes_: 

1) Instead of the `.test()` function used in kata 1, solution 3, we use the `.match()` function to extract the part of the string that matches the regex pattern. 

2) The `\d` character class is used to match digits.

3) The [`unary plus operator (+)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Unary_plus), much like the `Number()` function, converts values into numbers, if they aren't already numbers. 

---

## Kata 3: Correct the mistakes of the character recognition software
### Instructions
When documents (especially pretty old ones written with a typewriter), are digitized character recognition software often make mistakes.

Your task is correct the errors in the digitized text. You only have to handle the following mistakes:
- `S` is misinterpreted as `5`
- `O` is misinterpreted as `0`
- `I` is misinterpreted as `1`

The test cases contain numbers only by mistake.

---

### Breaking down the problem 

<u>Parameters</u>
The function receives one parameter: a string.

The string contains both letters and numbers.

<u>Returns</u>
The function should return one value: a string containing only letters.

<u>Examples</u>
The following test cases are provided by CodeWars.

```
"L0ND0N" => "LONDON"
"DUBL1N" => "DUBLIN"
"51NGAP0RE" => "SINGAPORE"
"BUDAPE5T" => "BUDAPEST"
PAR15" => "PARIS"
```

---

### Solution 1: Creating a new string from an array

```javascript
function correct(string) {
  const arr = [];
  string.split('').forEach(char => {
    if (char === '5') { arr.push('S'); } 
    else if (char === '0') { arr.push('O'); } 
    else if (char === '1') { arr.push('I'); } 
    else { arr.push(char); }
  });
  return arr.join('');
}
```

_Notes_: 

1) A new empty array is initiated so letters can be pushed into it.

2) The original string is then turned into an array using the [`.split()` method ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split)so we can loop over the array using the [`.forEach` array method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach). 

3) Inside the loop, we verify if the current character is one of the specified numbers and if it is, the correct letter is pushed into the array. If the character is already a letter, the letter is pushed into the array. 

4) We then turn the array back into a string using the [`.join()` method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join).

---

### Solution 2: Replacing each character separately

```javascript
function correct(string) {
  return string.replace(/5/g, 'S')
               .replace(/0/g, 'O')
               .replace(/1/g, 'I');
}
```

_Notes_: 

1) The [`.replace()` method](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace), as the name suggests, replaces the text/pattern specified in its first parameter with the text/pattern specified in the second parameter and returns a new string.

2) The method is called 3 times on the same object (string) with the help of [method chaining](https://www.geeksforgeeks.org/method-chaining-in-javascript/#:~:text=Method%20Chaining%20is%20a%20programming,in%20which%20it%20is%20called.). 

3) The `/g` flag at the end of the regular expression stands for global and is used to match not just the first occurrence, but all occurrences in the string. 

---

### Solution 3: Replacing all characters at once

```javascript
function correct(string) {
  const chars = {
    '5': 'S', 
    '0': 'O', 
    '1': 'I'
  };
  return string.replace(/[501]/g, key => chars[key]);
}
```

_Notes_: 

1) First an object is created to hold the incorrect number characters and their replacements. 

2) The `.replace()` method is then used to replace all incorrect characters at once instead of one by one. To achieve this, a function is provided as the second parameter that grabs the correct replacement from the object. 

---

**What solution did you implement?**
**What solution did you find the most elegant?**
**What solution did you have trouble understanding?**

**Let me know, I'd love to hear from you!**

**I hope you found this article helpful.**

---

Connect with me on ...
[Twitter](https://twitter.com/Nat_A_Number)
[GitHub](https://github.com/NatGeyzenTech)