timoxley / functional-javascript-workshop

A functional javascript workshop. No libraries required (i.e. no underscore), just ES5.
2.05k stars 438 forks source link

Basic: Reduce output not passing. #112

Closed gnomefire closed 9 years ago

gnomefire commented 9 years ago

Can you tell me why my code isn't passing? It returns an object with the correct keys and values, but they are not in the same order as in the expected result. here is my code:

function countWords(inputWords) {
    var result = {};
    inputWords.reduce(function(a, b){
            if (!result[b]){
                    result[b] = 1;
            }
            else {
                    result[b] = result[b] +1;
            }
        })
        return result;
}
module.exports = countWords;

Thanks!

ethangodt commented 9 years ago

Hey! I thought I'd chime in because this workshop has helped me so much in the past.

Your answer is actually not the same as the expected. Check the first key from the expected result list and find it within your list — in your object it won't be first, and it will be counted one fewer times than it should have been. Everything else is in the correct order; this means that you probably forgot to count the very first word.

\ Everything passed this is a SPOILER - if you're super stumped feel free to keep reading, but one o the best ways to learn is try to reduce the problem (pun intended) to determine which part is broken and explore from there - it might be best to just ignore my solution and seek it out for yourself **

This is happening because of the way the reduce function works. It can take two arguments: 1. the accumulator function that you're using to summarize the data, 2. the initial value to start accumulating to (i.e. what the value of 'a' is on the first iteration). If you don't include the optional initial value argument then the function will automatically take the first element from the array as the value of 'a' and then start iterating from the second elem. So, for you, this means that your function is taking the first word as the value of 'a' the first iteration through (b/c you are not passing the optional arg), and then is looping through all the values starting with the second. Therefore, the first word is just being forgotten.

Lastly, there is a better way to use reduce here. Essentially, you could better accomplish your strategy of declaring the result object outside of the function and then adding to it with a for loop or forEach loop. With reduce, you want to do all the accumulating within the function. You should set the initial value to be an empty object (so you don't skip the first word), then return that object after each time you add something to it (so it becomes the value of 'a' each iteration), and then your reduce function will return that finished object at the end.

Sorry for the novel... here is the code:

function countWords(inputWords) {
    // var result = {}; delete this here
    return inputWords.reduce(function(a, b){ // added return here for when the whole reduce function returns the finished object
            if (!a[b]){
                    a[b] = 1;
            }
            else {
                    a[b] = a[b] + 1;
            }
            return a; // whatever is return each iteration become the value of 'a' the next iteration
        }, {}); // added an empty object as the initial value - now 'a' is empty object the first time through instead of the first word
        // return result; delete this
}
module.exports = countWords;

Here is a link to my solutions to the challenges with some explanation if you get stumped like this on any others — feel free to suggest changes that might make them better: https://github.com/ethangodt/nodeschool-solutions/tree/master/functional-javascript

timoxley commented 9 years ago

@ethangodt wow nice writeup.

timoxley commented 9 years ago

Not sure if giving solutions like that should come with a spoiler alert though, since a lot of the solid understanding comes from figuring out out yourself for the first time.

ethangodt commented 9 years ago

@timoxley Agree. I'll add a comment at the top. Let me know if there is a better way to do this.

Btw, thanks so much for looking over these challenges. They've helped me a lot.

gnomefire commented 9 years ago

Thanks, @ethangodt I appreciate the explanation, and see where I went wrong. Also, thank you @timoxley for setting up these challenges. They are very helpful.