Taking a string and reversing certain words — Javascript
Write a function that takes in a string of one or more words, and returns the same string, but with all five or more letter words reversed. Strings passed in will consist of only letters and spaces. Spaces will be included only when more than one word is present.
The code I wrote reverses the whole string. I believe it is something with the if statement, it is not catching words greater than 5. My thinking when writing the code is to first convert the string into an array of words, use a for loop to run through the arrays and find the words that are greater than 5, then reverse the words greater than 5. I have found similar problems and this is how far I got searching for help. I'm stuck, any help would be greatly appreciated! I am new to coding and learning Javascript.
function spinWords(backward){
var sentence = "";
var separate = backward.split("");
for (var i = separate.length - 1; i >= 0; i--){
if (separate[i].length >= 1){
sentence += separate[i].split("").reverse().join("");
}
else {
sentence += "" + separate[i];
}
}
return sentence;
}
spinWords("Hey fellow warriors");
javascript arrays string
add a comment |
Write a function that takes in a string of one or more words, and returns the same string, but with all five or more letter words reversed. Strings passed in will consist of only letters and spaces. Spaces will be included only when more than one word is present.
The code I wrote reverses the whole string. I believe it is something with the if statement, it is not catching words greater than 5. My thinking when writing the code is to first convert the string into an array of words, use a for loop to run through the arrays and find the words that are greater than 5, then reverse the words greater than 5. I have found similar problems and this is how far I got searching for help. I'm stuck, any help would be greatly appreciated! I am new to coding and learning Javascript.
function spinWords(backward){
var sentence = "";
var separate = backward.split("");
for (var i = separate.length - 1; i >= 0; i--){
if (separate[i].length >= 1){
sentence += separate[i].split("").reverse().join("");
}
else {
sentence += "" + separate[i];
}
}
return sentence;
}
spinWords("Hey fellow warriors");
javascript arrays string
Your problem statement isnt 100% clear. Are you saying you only want to reverse words that are 5 characters or more long?
– Paul Rooney
Dec 30 '18 at 23:06
add a comment |
Write a function that takes in a string of one or more words, and returns the same string, but with all five or more letter words reversed. Strings passed in will consist of only letters and spaces. Spaces will be included only when more than one word is present.
The code I wrote reverses the whole string. I believe it is something with the if statement, it is not catching words greater than 5. My thinking when writing the code is to first convert the string into an array of words, use a for loop to run through the arrays and find the words that are greater than 5, then reverse the words greater than 5. I have found similar problems and this is how far I got searching for help. I'm stuck, any help would be greatly appreciated! I am new to coding and learning Javascript.
function spinWords(backward){
var sentence = "";
var separate = backward.split("");
for (var i = separate.length - 1; i >= 0; i--){
if (separate[i].length >= 1){
sentence += separate[i].split("").reverse().join("");
}
else {
sentence += "" + separate[i];
}
}
return sentence;
}
spinWords("Hey fellow warriors");
javascript arrays string
Write a function that takes in a string of one or more words, and returns the same string, but with all five or more letter words reversed. Strings passed in will consist of only letters and spaces. Spaces will be included only when more than one word is present.
The code I wrote reverses the whole string. I believe it is something with the if statement, it is not catching words greater than 5. My thinking when writing the code is to first convert the string into an array of words, use a for loop to run through the arrays and find the words that are greater than 5, then reverse the words greater than 5. I have found similar problems and this is how far I got searching for help. I'm stuck, any help would be greatly appreciated! I am new to coding and learning Javascript.
function spinWords(backward){
var sentence = "";
var separate = backward.split("");
for (var i = separate.length - 1; i >= 0; i--){
if (separate[i].length >= 1){
sentence += separate[i].split("").reverse().join("");
}
else {
sentence += "" + separate[i];
}
}
return sentence;
}
spinWords("Hey fellow warriors");
javascript arrays string
javascript arrays string
asked Dec 30 '18 at 23:01


xendezxendez
61
61
Your problem statement isnt 100% clear. Are you saying you only want to reverse words that are 5 characters or more long?
– Paul Rooney
Dec 30 '18 at 23:06
add a comment |
Your problem statement isnt 100% clear. Are you saying you only want to reverse words that are 5 characters or more long?
– Paul Rooney
Dec 30 '18 at 23:06
Your problem statement isnt 100% clear. Are you saying you only want to reverse words that are 5 characters or more long?
– Paul Rooney
Dec 30 '18 at 23:06
Your problem statement isnt 100% clear. Are you saying you only want to reverse words that are 5 characters or more long?
– Paul Rooney
Dec 30 '18 at 23:06
add a comment |
2 Answers
2
active
oldest
votes
You might find the logic a lot easier if you used a regular expression to match 5 or more word characters in a row, and use a replacer function to reverse
them:
function spinWords(backward) {
return backward.replace(/w{5,}/g, word => word.split('').reverse().join(''));
}
console.log(spinWords("Hey fellow warriors"));
To fix your code, you should split the input string (the variabla named backward
) by a space, not by the empty string, to get an array of words, then iterate through that array (starting from the beginning, not at the end), checking for each word's length
and concatenating with sentence
:
function spinWords(backward) {
var sentence = "";
var separate = backward.split(" ");
for (var i = 0; i < separate.length; i++) {
if (sentence) sentence += ' ';
if (separate[i].length >= 5) {
sentence += separate[i].split("").reverse().join("");
} else {
sentence += separate[i];
}
}
return sentence;
}
console.log(spinWords("Hey fellow warriors"));
add a comment |
Below is a discussion about a possible way to approach this problem. It is not what I would likely do for a question as simple as this, but it demonstrates a mindset that makes it easier to solve many problems, and to reuse your work as you do so.
Breaking the problem down
You want to do several things here, so it might help to break the problem down into steps.
At the core, you want to reverse certain words. So why not write a function to do only that? It should be simple. Here is one version:
const reverseWord = word => word.split('').reverse().join('')
reverseWord('word') //=> 'drow'
But you only want to do this to words whose length is at least five. Rather than rewriting our existing function, we can use it to write the more complex one:
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
reverseIfGte5('word') //=> 'word'
reverseIfGte5('supercalifragilisticexpialidocious')
//=> 'suoicodilaipxecitsiligarfilacrepus')
Note that here, we write reverseIfGte5
using reverseWord
. So our reverseWord
function is also available to be reused if we choose, but also so that each function is doing something simple.
We could now write spinWord
in terms of this function, via
const spinWords = sentence => sentence.split(/s+/).map(reverseIfGte5).join(' ')
spinWords('Hey fellow warriors') //=> 'Hey wollef sroirraw'
This does what's expected. And it might be a good place to stop. However...
Do only one thing per function
Our spinWords
function above is responsible for two things:
- finding the words in the sentence
- applying our reversing function to each
Ideally, a function should be responsible for one thing an one thing only. (There is some judgment to be made in deciding how such responsibilities break down, of course.)
It might be useful to break this apart. We can do that in different ways. Here's a simple one:
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
const spinWords = updateWords(reverseIfGte5)
Now we have a reusable function, which we could use, for instance, with an obvious capitalizeFirstLetter
function like this:
const titleCase = updateWords(capitalizeFirstLetter)
titleCase('Hey fellow warriors') //=> 'Hey Fellow Warriors')
Fixing bugs
Our code now looks like this:
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
These functions are ordered from the most likely to the least likely to be reusable.
Note that the total code here, when using such reusable functions, is a bit longer than this plain version:
const spinWords = sentence => sentence.split(/s+/).map(
word => word.length >= 5 ? word.split('').reverse().join('') : word
).join(' ')
But our version has several advantages. Obviously, reusability is one. But another is that with the problem broken down into small pieces, if we find a problem, we know where look to for a solution.
And guess what, there is in fact a potential bug in this solution.
If we call this function with 'Hey fellow warriors'
, we return 'Hey wollef oirraw'
instead of the expected 'Hey wollef sroirraw'
. Our spacing is off.
Because this problem is broken down into distinct functions, there is no question about which function we need to change in order to fix this. Clearly it is the function responsible for pulling apart and putting back together the sentence, updateWords
. There is one simple fix to this, changing from
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
to
const updateWords = wordFn => sentence => sentence.split(' ').map(wordFn).join(' ')
but we might be better off using a variant of the answer from CertainPerformance, and rewriting it like this:
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
This fixes the bug and actually handles more cases than we could have originally. (Note that it now deals with punctuation characters as well):
spinWords('Hey, fellow warriors!') //=> 'Hey, wollef sroirraw!'
The important point is that in order to fix our bug, we were able to isolate the function responsible and change it without changing anything else.
Working code
This is what we have arrived at:
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
console.log(spinWords('Hey, fellow warriors!'))
We have broken the problem down into two fairly reusable functions (reverseWord
and updateWords
), and two very specific to our problem (reverseIfGte5
and spinWords
.) Each has a well-defined responsibility, and they are easy to test in isolation.
Extending further
This is as far as I would likely go with such a function. But because my personal library often includes a function, when
, which is already a generalization of one of these, sometimes I might prefer to build on that:
const when = (cond, then) => val => cond(val) ? then(val) : val
const reverseIfGte5 = when(word => word.length >= 5, reverseWord)
I created when
because there are times when I want to use an altered version of my input if some condition is true about it and use it unaltered if the condition is false. That is exactly what reverseIfGte5
needs to do, so it's useful to build it on top of when
.
This is how utility libraries are built. Several specific problems have obvious connections and more general solutions to them are written to handle them. If these such solutions are generic enough, they are candidates for inclusion in your personal library or your team's library. And if they are useful to a wider audience, they might get included in a general-purpose utility library.
I'm one of the authors of Ramda, a utility library for functional programming in JS, and this is exactly how it has been built.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53982133%2ftaking-a-string-and-reversing-certain-words-javascript%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You might find the logic a lot easier if you used a regular expression to match 5 or more word characters in a row, and use a replacer function to reverse
them:
function spinWords(backward) {
return backward.replace(/w{5,}/g, word => word.split('').reverse().join(''));
}
console.log(spinWords("Hey fellow warriors"));
To fix your code, you should split the input string (the variabla named backward
) by a space, not by the empty string, to get an array of words, then iterate through that array (starting from the beginning, not at the end), checking for each word's length
and concatenating with sentence
:
function spinWords(backward) {
var sentence = "";
var separate = backward.split(" ");
for (var i = 0; i < separate.length; i++) {
if (sentence) sentence += ' ';
if (separate[i].length >= 5) {
sentence += separate[i].split("").reverse().join("");
} else {
sentence += separate[i];
}
}
return sentence;
}
console.log(spinWords("Hey fellow warriors"));
add a comment |
You might find the logic a lot easier if you used a regular expression to match 5 or more word characters in a row, and use a replacer function to reverse
them:
function spinWords(backward) {
return backward.replace(/w{5,}/g, word => word.split('').reverse().join(''));
}
console.log(spinWords("Hey fellow warriors"));
To fix your code, you should split the input string (the variabla named backward
) by a space, not by the empty string, to get an array of words, then iterate through that array (starting from the beginning, not at the end), checking for each word's length
and concatenating with sentence
:
function spinWords(backward) {
var sentence = "";
var separate = backward.split(" ");
for (var i = 0; i < separate.length; i++) {
if (sentence) sentence += ' ';
if (separate[i].length >= 5) {
sentence += separate[i].split("").reverse().join("");
} else {
sentence += separate[i];
}
}
return sentence;
}
console.log(spinWords("Hey fellow warriors"));
add a comment |
You might find the logic a lot easier if you used a regular expression to match 5 or more word characters in a row, and use a replacer function to reverse
them:
function spinWords(backward) {
return backward.replace(/w{5,}/g, word => word.split('').reverse().join(''));
}
console.log(spinWords("Hey fellow warriors"));
To fix your code, you should split the input string (the variabla named backward
) by a space, not by the empty string, to get an array of words, then iterate through that array (starting from the beginning, not at the end), checking for each word's length
and concatenating with sentence
:
function spinWords(backward) {
var sentence = "";
var separate = backward.split(" ");
for (var i = 0; i < separate.length; i++) {
if (sentence) sentence += ' ';
if (separate[i].length >= 5) {
sentence += separate[i].split("").reverse().join("");
} else {
sentence += separate[i];
}
}
return sentence;
}
console.log(spinWords("Hey fellow warriors"));
You might find the logic a lot easier if you used a regular expression to match 5 or more word characters in a row, and use a replacer function to reverse
them:
function spinWords(backward) {
return backward.replace(/w{5,}/g, word => word.split('').reverse().join(''));
}
console.log(spinWords("Hey fellow warriors"));
To fix your code, you should split the input string (the variabla named backward
) by a space, not by the empty string, to get an array of words, then iterate through that array (starting from the beginning, not at the end), checking for each word's length
and concatenating with sentence
:
function spinWords(backward) {
var sentence = "";
var separate = backward.split(" ");
for (var i = 0; i < separate.length; i++) {
if (sentence) sentence += ' ';
if (separate[i].length >= 5) {
sentence += separate[i].split("").reverse().join("");
} else {
sentence += separate[i];
}
}
return sentence;
}
console.log(spinWords("Hey fellow warriors"));
function spinWords(backward) {
return backward.replace(/w{5,}/g, word => word.split('').reverse().join(''));
}
console.log(spinWords("Hey fellow warriors"));
function spinWords(backward) {
return backward.replace(/w{5,}/g, word => word.split('').reverse().join(''));
}
console.log(spinWords("Hey fellow warriors"));
function spinWords(backward) {
var sentence = "";
var separate = backward.split(" ");
for (var i = 0; i < separate.length; i++) {
if (sentence) sentence += ' ';
if (separate[i].length >= 5) {
sentence += separate[i].split("").reverse().join("");
} else {
sentence += separate[i];
}
}
return sentence;
}
console.log(spinWords("Hey fellow warriors"));
function spinWords(backward) {
var sentence = "";
var separate = backward.split(" ");
for (var i = 0; i < separate.length; i++) {
if (sentence) sentence += ' ';
if (separate[i].length >= 5) {
sentence += separate[i].split("").reverse().join("");
} else {
sentence += separate[i];
}
}
return sentence;
}
console.log(spinWords("Hey fellow warriors"));
answered Dec 30 '18 at 23:03
CertainPerformanceCertainPerformance
93.3k165384
93.3k165384
add a comment |
add a comment |
Below is a discussion about a possible way to approach this problem. It is not what I would likely do for a question as simple as this, but it demonstrates a mindset that makes it easier to solve many problems, and to reuse your work as you do so.
Breaking the problem down
You want to do several things here, so it might help to break the problem down into steps.
At the core, you want to reverse certain words. So why not write a function to do only that? It should be simple. Here is one version:
const reverseWord = word => word.split('').reverse().join('')
reverseWord('word') //=> 'drow'
But you only want to do this to words whose length is at least five. Rather than rewriting our existing function, we can use it to write the more complex one:
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
reverseIfGte5('word') //=> 'word'
reverseIfGte5('supercalifragilisticexpialidocious')
//=> 'suoicodilaipxecitsiligarfilacrepus')
Note that here, we write reverseIfGte5
using reverseWord
. So our reverseWord
function is also available to be reused if we choose, but also so that each function is doing something simple.
We could now write spinWord
in terms of this function, via
const spinWords = sentence => sentence.split(/s+/).map(reverseIfGte5).join(' ')
spinWords('Hey fellow warriors') //=> 'Hey wollef sroirraw'
This does what's expected. And it might be a good place to stop. However...
Do only one thing per function
Our spinWords
function above is responsible for two things:
- finding the words in the sentence
- applying our reversing function to each
Ideally, a function should be responsible for one thing an one thing only. (There is some judgment to be made in deciding how such responsibilities break down, of course.)
It might be useful to break this apart. We can do that in different ways. Here's a simple one:
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
const spinWords = updateWords(reverseIfGte5)
Now we have a reusable function, which we could use, for instance, with an obvious capitalizeFirstLetter
function like this:
const titleCase = updateWords(capitalizeFirstLetter)
titleCase('Hey fellow warriors') //=> 'Hey Fellow Warriors')
Fixing bugs
Our code now looks like this:
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
These functions are ordered from the most likely to the least likely to be reusable.
Note that the total code here, when using such reusable functions, is a bit longer than this plain version:
const spinWords = sentence => sentence.split(/s+/).map(
word => word.length >= 5 ? word.split('').reverse().join('') : word
).join(' ')
But our version has several advantages. Obviously, reusability is one. But another is that with the problem broken down into small pieces, if we find a problem, we know where look to for a solution.
And guess what, there is in fact a potential bug in this solution.
If we call this function with 'Hey fellow warriors'
, we return 'Hey wollef oirraw'
instead of the expected 'Hey wollef sroirraw'
. Our spacing is off.
Because this problem is broken down into distinct functions, there is no question about which function we need to change in order to fix this. Clearly it is the function responsible for pulling apart and putting back together the sentence, updateWords
. There is one simple fix to this, changing from
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
to
const updateWords = wordFn => sentence => sentence.split(' ').map(wordFn).join(' ')
but we might be better off using a variant of the answer from CertainPerformance, and rewriting it like this:
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
This fixes the bug and actually handles more cases than we could have originally. (Note that it now deals with punctuation characters as well):
spinWords('Hey, fellow warriors!') //=> 'Hey, wollef sroirraw!'
The important point is that in order to fix our bug, we were able to isolate the function responsible and change it without changing anything else.
Working code
This is what we have arrived at:
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
console.log(spinWords('Hey, fellow warriors!'))
We have broken the problem down into two fairly reusable functions (reverseWord
and updateWords
), and two very specific to our problem (reverseIfGte5
and spinWords
.) Each has a well-defined responsibility, and they are easy to test in isolation.
Extending further
This is as far as I would likely go with such a function. But because my personal library often includes a function, when
, which is already a generalization of one of these, sometimes I might prefer to build on that:
const when = (cond, then) => val => cond(val) ? then(val) : val
const reverseIfGte5 = when(word => word.length >= 5, reverseWord)
I created when
because there are times when I want to use an altered version of my input if some condition is true about it and use it unaltered if the condition is false. That is exactly what reverseIfGte5
needs to do, so it's useful to build it on top of when
.
This is how utility libraries are built. Several specific problems have obvious connections and more general solutions to them are written to handle them. If these such solutions are generic enough, they are candidates for inclusion in your personal library or your team's library. And if they are useful to a wider audience, they might get included in a general-purpose utility library.
I'm one of the authors of Ramda, a utility library for functional programming in JS, and this is exactly how it has been built.
add a comment |
Below is a discussion about a possible way to approach this problem. It is not what I would likely do for a question as simple as this, but it demonstrates a mindset that makes it easier to solve many problems, and to reuse your work as you do so.
Breaking the problem down
You want to do several things here, so it might help to break the problem down into steps.
At the core, you want to reverse certain words. So why not write a function to do only that? It should be simple. Here is one version:
const reverseWord = word => word.split('').reverse().join('')
reverseWord('word') //=> 'drow'
But you only want to do this to words whose length is at least five. Rather than rewriting our existing function, we can use it to write the more complex one:
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
reverseIfGte5('word') //=> 'word'
reverseIfGte5('supercalifragilisticexpialidocious')
//=> 'suoicodilaipxecitsiligarfilacrepus')
Note that here, we write reverseIfGte5
using reverseWord
. So our reverseWord
function is also available to be reused if we choose, but also so that each function is doing something simple.
We could now write spinWord
in terms of this function, via
const spinWords = sentence => sentence.split(/s+/).map(reverseIfGte5).join(' ')
spinWords('Hey fellow warriors') //=> 'Hey wollef sroirraw'
This does what's expected. And it might be a good place to stop. However...
Do only one thing per function
Our spinWords
function above is responsible for two things:
- finding the words in the sentence
- applying our reversing function to each
Ideally, a function should be responsible for one thing an one thing only. (There is some judgment to be made in deciding how such responsibilities break down, of course.)
It might be useful to break this apart. We can do that in different ways. Here's a simple one:
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
const spinWords = updateWords(reverseIfGte5)
Now we have a reusable function, which we could use, for instance, with an obvious capitalizeFirstLetter
function like this:
const titleCase = updateWords(capitalizeFirstLetter)
titleCase('Hey fellow warriors') //=> 'Hey Fellow Warriors')
Fixing bugs
Our code now looks like this:
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
These functions are ordered from the most likely to the least likely to be reusable.
Note that the total code here, when using such reusable functions, is a bit longer than this plain version:
const spinWords = sentence => sentence.split(/s+/).map(
word => word.length >= 5 ? word.split('').reverse().join('') : word
).join(' ')
But our version has several advantages. Obviously, reusability is one. But another is that with the problem broken down into small pieces, if we find a problem, we know where look to for a solution.
And guess what, there is in fact a potential bug in this solution.
If we call this function with 'Hey fellow warriors'
, we return 'Hey wollef oirraw'
instead of the expected 'Hey wollef sroirraw'
. Our spacing is off.
Because this problem is broken down into distinct functions, there is no question about which function we need to change in order to fix this. Clearly it is the function responsible for pulling apart and putting back together the sentence, updateWords
. There is one simple fix to this, changing from
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
to
const updateWords = wordFn => sentence => sentence.split(' ').map(wordFn).join(' ')
but we might be better off using a variant of the answer from CertainPerformance, and rewriting it like this:
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
This fixes the bug and actually handles more cases than we could have originally. (Note that it now deals with punctuation characters as well):
spinWords('Hey, fellow warriors!') //=> 'Hey, wollef sroirraw!'
The important point is that in order to fix our bug, we were able to isolate the function responsible and change it without changing anything else.
Working code
This is what we have arrived at:
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
console.log(spinWords('Hey, fellow warriors!'))
We have broken the problem down into two fairly reusable functions (reverseWord
and updateWords
), and two very specific to our problem (reverseIfGte5
and spinWords
.) Each has a well-defined responsibility, and they are easy to test in isolation.
Extending further
This is as far as I would likely go with such a function. But because my personal library often includes a function, when
, which is already a generalization of one of these, sometimes I might prefer to build on that:
const when = (cond, then) => val => cond(val) ? then(val) : val
const reverseIfGte5 = when(word => word.length >= 5, reverseWord)
I created when
because there are times when I want to use an altered version of my input if some condition is true about it and use it unaltered if the condition is false. That is exactly what reverseIfGte5
needs to do, so it's useful to build it on top of when
.
This is how utility libraries are built. Several specific problems have obvious connections and more general solutions to them are written to handle them. If these such solutions are generic enough, they are candidates for inclusion in your personal library or your team's library. And if they are useful to a wider audience, they might get included in a general-purpose utility library.
I'm one of the authors of Ramda, a utility library for functional programming in JS, and this is exactly how it has been built.
add a comment |
Below is a discussion about a possible way to approach this problem. It is not what I would likely do for a question as simple as this, but it demonstrates a mindset that makes it easier to solve many problems, and to reuse your work as you do so.
Breaking the problem down
You want to do several things here, so it might help to break the problem down into steps.
At the core, you want to reverse certain words. So why not write a function to do only that? It should be simple. Here is one version:
const reverseWord = word => word.split('').reverse().join('')
reverseWord('word') //=> 'drow'
But you only want to do this to words whose length is at least five. Rather than rewriting our existing function, we can use it to write the more complex one:
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
reverseIfGte5('word') //=> 'word'
reverseIfGte5('supercalifragilisticexpialidocious')
//=> 'suoicodilaipxecitsiligarfilacrepus')
Note that here, we write reverseIfGte5
using reverseWord
. So our reverseWord
function is also available to be reused if we choose, but also so that each function is doing something simple.
We could now write spinWord
in terms of this function, via
const spinWords = sentence => sentence.split(/s+/).map(reverseIfGte5).join(' ')
spinWords('Hey fellow warriors') //=> 'Hey wollef sroirraw'
This does what's expected. And it might be a good place to stop. However...
Do only one thing per function
Our spinWords
function above is responsible for two things:
- finding the words in the sentence
- applying our reversing function to each
Ideally, a function should be responsible for one thing an one thing only. (There is some judgment to be made in deciding how such responsibilities break down, of course.)
It might be useful to break this apart. We can do that in different ways. Here's a simple one:
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
const spinWords = updateWords(reverseIfGte5)
Now we have a reusable function, which we could use, for instance, with an obvious capitalizeFirstLetter
function like this:
const titleCase = updateWords(capitalizeFirstLetter)
titleCase('Hey fellow warriors') //=> 'Hey Fellow Warriors')
Fixing bugs
Our code now looks like this:
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
These functions are ordered from the most likely to the least likely to be reusable.
Note that the total code here, when using such reusable functions, is a bit longer than this plain version:
const spinWords = sentence => sentence.split(/s+/).map(
word => word.length >= 5 ? word.split('').reverse().join('') : word
).join(' ')
But our version has several advantages. Obviously, reusability is one. But another is that with the problem broken down into small pieces, if we find a problem, we know where look to for a solution.
And guess what, there is in fact a potential bug in this solution.
If we call this function with 'Hey fellow warriors'
, we return 'Hey wollef oirraw'
instead of the expected 'Hey wollef sroirraw'
. Our spacing is off.
Because this problem is broken down into distinct functions, there is no question about which function we need to change in order to fix this. Clearly it is the function responsible for pulling apart and putting back together the sentence, updateWords
. There is one simple fix to this, changing from
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
to
const updateWords = wordFn => sentence => sentence.split(' ').map(wordFn).join(' ')
but we might be better off using a variant of the answer from CertainPerformance, and rewriting it like this:
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
This fixes the bug and actually handles more cases than we could have originally. (Note that it now deals with punctuation characters as well):
spinWords('Hey, fellow warriors!') //=> 'Hey, wollef sroirraw!'
The important point is that in order to fix our bug, we were able to isolate the function responsible and change it without changing anything else.
Working code
This is what we have arrived at:
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
console.log(spinWords('Hey, fellow warriors!'))
We have broken the problem down into two fairly reusable functions (reverseWord
and updateWords
), and two very specific to our problem (reverseIfGte5
and spinWords
.) Each has a well-defined responsibility, and they are easy to test in isolation.
Extending further
This is as far as I would likely go with such a function. But because my personal library often includes a function, when
, which is already a generalization of one of these, sometimes I might prefer to build on that:
const when = (cond, then) => val => cond(val) ? then(val) : val
const reverseIfGte5 = when(word => word.length >= 5, reverseWord)
I created when
because there are times when I want to use an altered version of my input if some condition is true about it and use it unaltered if the condition is false. That is exactly what reverseIfGte5
needs to do, so it's useful to build it on top of when
.
This is how utility libraries are built. Several specific problems have obvious connections and more general solutions to them are written to handle them. If these such solutions are generic enough, they are candidates for inclusion in your personal library or your team's library. And if they are useful to a wider audience, they might get included in a general-purpose utility library.
I'm one of the authors of Ramda, a utility library for functional programming in JS, and this is exactly how it has been built.
Below is a discussion about a possible way to approach this problem. It is not what I would likely do for a question as simple as this, but it demonstrates a mindset that makes it easier to solve many problems, and to reuse your work as you do so.
Breaking the problem down
You want to do several things here, so it might help to break the problem down into steps.
At the core, you want to reverse certain words. So why not write a function to do only that? It should be simple. Here is one version:
const reverseWord = word => word.split('').reverse().join('')
reverseWord('word') //=> 'drow'
But you only want to do this to words whose length is at least five. Rather than rewriting our existing function, we can use it to write the more complex one:
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
reverseIfGte5('word') //=> 'word'
reverseIfGte5('supercalifragilisticexpialidocious')
//=> 'suoicodilaipxecitsiligarfilacrepus')
Note that here, we write reverseIfGte5
using reverseWord
. So our reverseWord
function is also available to be reused if we choose, but also so that each function is doing something simple.
We could now write spinWord
in terms of this function, via
const spinWords = sentence => sentence.split(/s+/).map(reverseIfGte5).join(' ')
spinWords('Hey fellow warriors') //=> 'Hey wollef sroirraw'
This does what's expected. And it might be a good place to stop. However...
Do only one thing per function
Our spinWords
function above is responsible for two things:
- finding the words in the sentence
- applying our reversing function to each
Ideally, a function should be responsible for one thing an one thing only. (There is some judgment to be made in deciding how such responsibilities break down, of course.)
It might be useful to break this apart. We can do that in different ways. Here's a simple one:
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
const spinWords = updateWords(reverseIfGte5)
Now we have a reusable function, which we could use, for instance, with an obvious capitalizeFirstLetter
function like this:
const titleCase = updateWords(capitalizeFirstLetter)
titleCase('Hey fellow warriors') //=> 'Hey Fellow Warriors')
Fixing bugs
Our code now looks like this:
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
These functions are ordered from the most likely to the least likely to be reusable.
Note that the total code here, when using such reusable functions, is a bit longer than this plain version:
const spinWords = sentence => sentence.split(/s+/).map(
word => word.length >= 5 ? word.split('').reverse().join('') : word
).join(' ')
But our version has several advantages. Obviously, reusability is one. But another is that with the problem broken down into small pieces, if we find a problem, we know where look to for a solution.
And guess what, there is in fact a potential bug in this solution.
If we call this function with 'Hey fellow warriors'
, we return 'Hey wollef oirraw'
instead of the expected 'Hey wollef sroirraw'
. Our spacing is off.
Because this problem is broken down into distinct functions, there is no question about which function we need to change in order to fix this. Clearly it is the function responsible for pulling apart and putting back together the sentence, updateWords
. There is one simple fix to this, changing from
const updateWords = wordFn => sentence => sentence.split(/s+/).map(wordFn).join(' ')
to
const updateWords = wordFn => sentence => sentence.split(' ').map(wordFn).join(' ')
but we might be better off using a variant of the answer from CertainPerformance, and rewriting it like this:
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
This fixes the bug and actually handles more cases than we could have originally. (Note that it now deals with punctuation characters as well):
spinWords('Hey, fellow warriors!') //=> 'Hey, wollef sroirraw!'
The important point is that in order to fix our bug, we were able to isolate the function responsible and change it without changing anything else.
Working code
This is what we have arrived at:
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
console.log(spinWords('Hey, fellow warriors!'))
We have broken the problem down into two fairly reusable functions (reverseWord
and updateWords
), and two very specific to our problem (reverseIfGte5
and spinWords
.) Each has a well-defined responsibility, and they are easy to test in isolation.
Extending further
This is as far as I would likely go with such a function. But because my personal library often includes a function, when
, which is already a generalization of one of these, sometimes I might prefer to build on that:
const when = (cond, then) => val => cond(val) ? then(val) : val
const reverseIfGte5 = when(word => word.length >= 5, reverseWord)
I created when
because there are times when I want to use an altered version of my input if some condition is true about it and use it unaltered if the condition is false. That is exactly what reverseIfGte5
needs to do, so it's useful to build it on top of when
.
This is how utility libraries are built. Several specific problems have obvious connections and more general solutions to them are written to handle them. If these such solutions are generic enough, they are candidates for inclusion in your personal library or your team's library. And if they are useful to a wider audience, they might get included in a general-purpose utility library.
I'm one of the authors of Ramda, a utility library for functional programming in JS, and this is exactly how it has been built.
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
console.log(spinWords('Hey, fellow warriors!'))
const updateWords = wordFn => sentence => sentence.replace(/w+/g, wordFn)
const reverseWord = word => word.split('').reverse().join('')
const reverseIfGte5 = word => word.length >= 5 ? reverseWord(word) : word
const spinWords = updateWords(reverseIfGte5)
console.log(spinWords('Hey, fellow warriors!'))
edited Jan 1 at 21:22
answered Dec 31 '18 at 3:16
Scott SauyetScott Sauyet
21k22757
21k22757
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53982133%2ftaking-a-string-and-reversing-certain-words-javascript%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Your problem statement isnt 100% clear. Are you saying you only want to reverse words that are 5 characters or more long?
– Paul Rooney
Dec 30 '18 at 23:06