Home > Blockchain >  Write a recursive function called capitalizeFirst. Given an array of strings, capitalize the first l
Write a recursive function called capitalizeFirst. Given an array of strings, capitalize the first l

Time:10-02

I see this similar algorithm was posted on stackoverflow, nevertheless I cannot understand, so I decided to post once more.

function capitalizeWords(arr) {
  if (arr.length === 1) {
    return [arr[0].toUpperCase()]
  }
  let res = capitalizeWords(arr.slice(0, -1))
  res.push(arr.slice(arr.length - 1)[0].toUpperCase())
  return res
}

console.log(capitalizeWords(['dog', 'car', 'horse']))

Things I do not understand...

  1. Why it is inside square brackets return [arr[0].toUpperCase()] why not just return arr[0].toUpperCase()
  2. Why "arr" is getting sliced twice:

here

let res = capitalizeWords(arr.slice(0,-1)

and here

res.push(arr.slice(arr.length-1)[0].toUpperCase())

Overall, I am lost, please help

CodePudding user response:

I see that the OP wants to explain some found code. First, it's not very good code. The function can be restated in a couple easy to read lines.

Here's the not-so-good code annotated (comments *in stars* answer the specific OP questions)

function capitalizeWords(arr) {
  // this is the degenerate case: a single item array
  if (arr.length === 1) {
    return [arr[0].toUpperCase()]  // return a *single item array* with the one element capitalized
    // incidentally, toUpperCase capitalizes all letters, not only the first, as stated in the OP title
  }
  // here, there must be length > 1, run the function on the array minus the last element
  // it will return an array (see above) for that last element
  let res = capitalizeWords(arr.slice(0, -1))
  // this says capitalize the last element.
  // it's super clumsy, grabbing the last element by *slicing the array again* just before the end,
  // getting that one element from the slice, and using with toUpperCase
  // then pushing that uppercase result onto the result array
  res.push(arr.slice(arr.length - 1)[0].toUpperCase())
  return res
}

Here's a cleanup. First, isolate the capitalization logic and get that tested and correct. It will look like this:

const capitalizeWord = word => word[0].toUpperCase()   word.slice(1);

Next, realize that the most degenerate (elemental) case is capitalizing an empty array. The result of capitalizing an empty array is an empty array.

// something like
return !arr.length ? [] : // ... recursion will go here

When recursing with arrays, we generally say: "do something with the first element, and do the function with the rest of the elements". In JS, it's much more elegant to refer to the "first and rest" than to "all but the last and the last".

// first element (after we've established > 0 length)
arr[0]

// the rest of the elements
arr.slice(1)

Putting this all together...

const capitalizeWord = word => word[0].toUpperCase()   word.slice(1);


function capitalizeWords(arr) {
  return arr.length ? [ capitalizeWord(arr[0]), ...capitalizeWords(arr.slice(1))] : [];
}

console.log(capitalizeWords(['dog', 'car', 'horse']))

CodePudding user response:

I would forget about what that code does and concentrate on the steps you need to take to make your function work.

  1. Recursive - so the function needs to call itself but you need to find a way to identify which element you're working on.

  2. You need a way to break out of the recursion when you reach the end of the array.

  3. You need a way to separate out the first letter of an element from all the rest, and update the element with a transformed string.

Here's how I might approach it.

// Pass in the array, and initialise an index
// variable
function capitalizeFirst(arr, index = 0) {
  
  if (!arr.length) return 'Empty array';

  // If we're at the end of the array
  // return the array
  if (index === arr.length) return arr;
  
  // If the element is not empty
  if (arr[index].length) {
  
    // Get the first letter, and place all
    // the other letters in an array called `rest`
    // You can use destructuring here because strings
    // are iterable
    const [first, ...rest] = arr[index];

    // Update the element at the current index
    // with the new string making sure you join up `rest`
    arr[index] = `${first.toUpperCase()}${rest.join('')}`;
  
  }

  // Call the function again increasing the index
  return capitalizeFirst(arr,   index);
}

console.log(capitalizeFirst(['dog', 'car', 'horse']));
console.log(capitalizeFirst([]));
console.log(capitalizeFirst(['dog', '', 'horse']));
console.log(capitalizeFirst(['dog', 'o', 'horse']));

Additional documentation

CodePudding user response:

your confusion code

1.let res = capitalizeWords(arr.slice(0,-1)
2.res.push(arr.slice(arr.length-1)[0].toUpperCase())

1.res is an variable array . when this line of code will run let res = capitalizeWords(arr.slice(0,-1)) that means first thing will be done is from your array ['dog', 'car', 'horse'] it will take out the first item that is "dog" and after capitalizeWords function will run and inside capitalizeWords function the argument passed from res is "dog" . and when the function will run if block will run because now arr has one element that is ["dog"] and that will be converted to ["DOG"] . and as like this ['car', 'horse'] this 2 elements will be converted to capital . but it is a bit complex code to understand as a beginner.

so,you can use my simplify code . i hope you can understand this easily !!

function capitalizeWords(arr) {
  if(arr.length === 1) {
    return [arr[0].toUpperCase()]
  }
  let res = []
  for (let i of arr){
    res.push(i.toUpperCase())
  }
  return res
}

console.log(capitalizeWords(['dog', 'car', 'horse']))

your another confusion is

return [arr[0].toUpperCase()]

if you write return arr[0].toUpperCase() that means arr[0]="dog" (its a string not an array) . if you just want to print it as a string then you can write arr[0].toUpperCase() :"dog" but if you want to console it as an array then you have to write this : [arr[0].toUpperCase()] :["dog"]

CodePudding user response:

Update

Added some input checking:

if (array.length < 1) return `ERROR Empty Array`;
// Return error message if input is an empty array

if (typeof str === "string" && /[a-z]/.test(str.charAt(0))) {...
/**
 * Ignore all non-string data and any string that doesn't start with  
 * a lower case letter
 */

The code in OP doesn't capitalize each word in an array, it capitalizes every letter of each word. I honestly didn't really try to figure out what's exactly wrong because there's no recursion in the OP anyhow.

Recursion

  1. A function that calls itself within the function (which is itself).
  2. A base condition must be met in order for the function to call itself.
  3. The parameters should change upon each recurse.
  4. The function will cease calling itself once the base condition is no longer true.

In the OP, there's no base condition (see Recursion 2).

In the following example is a recursive function that capitalizes each word of an array.

  • Pass in the array and index (if index is undefined it defaults to 0)
    function capWords(array, index = 0) {...
    // array = ["dog", "cat', 'bird'], index = 0
    
  • Find the word from the array at the index
    let str = array[index];
    // str = 'dog'
    
  • Get the first letter of that word and capitalize it
    let cap = str.charAt(0).toUpperCase();
    // cap = "D"
    
  • Then concatenate cap to the rest of that word and then reassign the new word to the array at index
    array[index] = cap   str.slice(1);
    // array = ['Dog', 'cat', 'bird']
    
  • If index is less than the length of the array -1...
    if (index < array.length - 1) {...
    /**
     * See Recursion 2
     * index = 0, array.length -1 = 2
     */
    
  • ...return and call capWords(array, index 1)...
    return capWords(array, index   1)
    /** 
     * See Recursion 1
     * array = ['Dog', 'cat', 'bird'], index = 1
     * See Recursion 3
     */
    
  • ...otherwise return array
    return array
    /** 
     * See Recursion 4
     * After calling capWords() recursively 2 more times, the array is  
     * returned one more time
     * array = ["Dog", "Cat", "Bird"]
     */
    

function capWords(array, index = 0) {
  if (array.length < 1) return `ERROR Empty Array`;
  let str = array[index];
  if (typeof str === "string" && /[a-z]/.test(str.charAt(0))) {
    let cap = str.charAt(0).toUpperCase();
    array[index] = cap   str.slice(1);
  }
  if (index < array.length - 1) {
    return capWords(array, index   1);
  }
  return array;
}

console.log(capWords(['dog', 'cat', 'bird'], 0));
console.log(capWords(['dog', '', 'bird']));
console.log(capWords([2, 'cat', 'bird'], 0));
console.log(capWords(['dog', 'cat', {}], 0));
console.log(capWords([]));

  • Related