0
\$\begingroup\$

What I need is to remove first word from the string again and again until only one word is left, and put it all into array.

For example, I have this string as an input:

Chicago IL 12345 United States

What I need to achieve is this array:

[ 'Chicago IL 12345 United States',
'IL 12345 United States',
'12345 United States',
'United States',
'States' ]

My code works but I wanted to get rid of the second param, and maybe make the code shorter and look more beautiful.

Here is what I currently have:

const stringToArray = (str, arr) => {
  const result = arr || [];
  const wordArray = str.split(' ');
  const len = wordArray.length;
  result.push(str);

  if (len === 1) {
    return arr;
  }

  return stringToArray(wordArray.slice((-1 * len) + 1).join(' '), result);
};

const partsArray = stringToArray('Chicago IL 12345 United States');

console.log(partsArray);

\$\endgroup\$
3
\$\begingroup\$

If you don't need using recursion, this is an alternative where you can get rid of the second param of the function.

const stringToArray = (str) => {
  const result = [];
  let wordArray = str.split(' ');
  
  while(wordArray.length > 0) {
    result.push(wordArray.join(' '));
    wordArray = wordArray.slice(1);
  }
  
  return result;
};

const partsArray = stringToArray('Chicago IL 12345 United States');

console.log(partsArray);

\$\endgroup\$
2
\$\begingroup\$

If you're targeting a recent javascript engine you can use default parameters which would save you line #2.

Additionally, to improve readability I'd recommend moving the string slicing to its own line, and I'd also use a name other than len to represent the number of words remaining. Clean Code by Robert Martin is a great resource for learning how to improve code readability.

const stringToArray = (str, result = []) => {
  const wordArray = str.split(' ');
  const numberOfRemainingWords = wordArray.length;
  result.push(str);

  if (numberOfRemainingWords === 1) {
    return arr;
  }

  const remainingWords = wordArray.slice((-1 * numberOfRemainingWords) + 1).join(' ');
  return stringToArray(remainingWords, result);
};

const partsArray = stringToArray('Chicago IL 12345 United States');

console.log(partsArray);

\$\endgroup\$
1
\$\begingroup\$

You can use reduce to achieve the same functionality in a shorter form which is also more readable.

If you take a close look you can find an upward growing pattern which starts with the last word to the first one:

   ...
    ^
    |
*12345* United States
    ^
    |
*United* States
    ^
    |
*States*

It's like you started with the last word, added the second last word before it and then the third last word, etc.

So in order to loop through this, we need to reverse your words list to start with the last word:

string.split(' ').reverse()

Then what's left to do is to take the last string and add the new word to it. Knowing that we grow the list upwards, the first element always is the most recently built one, therefore we just concatenate the current word to its left side and add the result to the first element of the list:

 .reduce((w, s) => [w[0] ? `${s} ${w[0]}` : s, ...w], []);

Notes:

  • w is the current accumulated word list, and s is the nth last word
  • w[0] ? `${s} ${w[0]}` : s ensures the first word is being concatenated without spaces
  • We grow the list of sentences upwards, so we add the current string to the left of the accumulated words.

const stringToArray = string => string.split(' ').reverse()
  .reduce((w, s) => [w[0] ? `${s} ${w[0]}` : s, ...w], []);

const partsArray = stringToArray('Chicago IL 12345 United States');

console.log(partsArray);

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

I would consider using a Regex. Something like:

result=[string]; 
while (string.match(/\s/)) { 
  string=string.replace(/^\S*\s+/,''); 
  result.push(string) 
}
return result;
\$\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.