Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic Recursion: Simpler solution #32

Open
17xande opened this issue Nov 19, 2013 · 15 comments
Open

Basic Recursion: Simpler solution #32

17xande opened this issue Nov 19, 2013 · 15 comments

Comments

@17xande
Copy link

17xande commented Nov 19, 2013

I may have found a simpler solution to the recursion problem:

function reduce(arr, fn, initial) {
    if (arr.length === 0) {
        return initial;
    }

    return fn(initial, arr.shift(), 0, arr);
}

module.exports = reduce;

I'm not sure how this solution compares to the one provided, perhaps it's less efficient, or maybe it doesn't work on all cases, but it makes more sense in my head, mostly because it seems a bit simpler. It also passes the test successfully.

Additionally, I had to read the problem description like 10 times before I thought I understood what was required.
i.e. Part of the description reads: "... and an initial value which will return an object containing the counts for each word found in the array ...".
That sounds like the initial value will return an object? So my first thought was: is the initial value a function as well?
Eventually I figured it out. Maybe I'm the only one that struggled with the description, otherwise, perhaps we could improve it slightly? Just a thought...

@timoxley
Copy link
Owner

Ahh, your solution only performs a single step. Try this:

reduce([1,2,3], function(prev, curr) {
  return prev + curr
}, 0)

It should output 6.

Sounds like we need a more rigorous test.

And yes, the problem description is a bit tricky too, perhaps we could simplify it to the example I did above, just a simple accumulator as the actual operation isn't important, just that you've figured out how to emulate reduce with recursion correctly

@joyrexus
Copy link

Along similar lines, but this works:

  // reduce `arr` with `reduction` method
  // initialize with `init`
  var reduce = function(arr, reduction, init) {
    if (!arr.length) { return init }              // nothing left to recur over
    var next = arr.shift();                       // shift off first value
    var reduced = reduction(init, next, 0, arr);  // get reduced value
    return reduce(arr, reduction, reduced);       // recur
  };

@timoxley
Copy link
Owner

timoxley commented Jan 1, 2014

@joyrexus I like it, though compared with 'real' reduce, in your solution the index param is always 0.

@joyrexus
Copy link

joyrexus commented Jan 1, 2014

@timoxley ah, true. We can increment the index, albeit at the expense of concision:

  // reduce `arr` with `reduction` method
  // initialize with `init`
  var reduce = function(arr, reduction, init) {
    var i, next, reduced;
    if (!arr.length) return init                        // nothing left to recur
    if (typeof i === "undefined" || i === null) i = 0   // increment index
    next = arr.shift();                                 // shift off first val
    reduced = reduction(init, next, i + 1, arr);        // get reduced value
    return reduce(arr, reduction, reduced);             // recur
  };

@joyrexus
Copy link

joyrexus commented Jan 1, 2014

FWIW, this elaboration of the original solution (renaming and commenting in the manner of the answer above) helped me better understand what was going on:

# reduce `arr` with `reduction` method
# initialize with `init`
reduce = (arr, reduction, init) ->
  max = arr.length - 1        # max of array index
  recur = (i, prev) ->
    return prev if i > max    # return prev value if no more values to recur over
    reduced = reduction(prev, arr[i], i, arr)
    recur(i + 1, reduced)     # recur on next with reduced value
  recur(0, init)              # start recursion

@Monocotyledon
Copy link

At a coder meetup last night, I got someone to walk me through the conceptual requirements of recursion, so I simply used

module.exports = function reduce(arr, fn, initial) {    # setup function w/target, operator, and initial value 
    if (arr.length === 0) {return initial};             # base case, does not recurse
    initial = fn(initial, arr[0]);                      # sets init-OP-first result as new init
    return reduce(arr.slice(1), fn, initial);}          # rightshifts first so arr[0] index is the new current value

Once I submitted it, I found the official solution hard to understand. Though it seems like you write a lot about how recursive functions are generally better and more elegant than loops, the official solution acts in a very looplike manner--it operates by incrementing the value of arr that the function is looking at. It seems like an unnecessarily long and complex method of reducing an array. In my experience, the longer code is, the more likely bugs escape notice and the harder for novices to learn the concept, which seems like your intention with this workshop.
I also found this exercise difficult to understand because the linked resources didn't include the link for array.prototype.split, which my recommendation would be to add. Actually, as a novice freshly learning this stuff, I could help alter the descriptions of the exercises to be considerably more friendly to complete code-newbies using this workshop.
-LMM

@joyrexus
Copy link

@Monocotyledon:

Actually, as a novice freshly learning this stuff, I could help alter the descriptions of the exercises to be considerably more friendly to complete code-newbies using this workshop.

Go for it! I don't think @timoxley is averse to pull requests.

@brookemitchell
Copy link

@Monocotyledon Definately like your solution more, I approached it similarly. Its the kind of approach I remember from How to Design Programs for dealing with recursion.

@timoxley
Copy link
Owner

timoxley commented Dec 3, 2014

Thanks for the input, I'm going to have a look at this over the weekend, will get back to you then!

@jakeseltz
Copy link

Functional-Javascript-Workshop : Reduce

Wrote out the reduce module as follows. It doesn't handle the undefined (I'm fairly new to javascript and not sure best how to handle the undefined.


  function countStrings(inputWords) {

      var list = inputWords.reduce(function(p,c){
        if(c in p){
            p[c]++
        }else{
            p[c]=1;
        }

        return p;

      }, {});
      console.log(list)
    }



    module.exports = countStrings

@kierans
Copy link

kierans commented Jan 8, 2015

My first attempt at the Basic Recursion exercise was very similar to @Monocotyledon however I defaulted the index value to fn to zero initially. Running my code through the verification process, my program passed. Eventually I thought of how to increment the index properly; for the sake of completing the problem properly. However the verification step should fail if the index isn't correct for each invocation of fn IMO since you're not meeting the requirements.

I'm guessing based on this thread that the calculation of the index is the hardest part of the problem, so feedback for users would also be useful.

I also think the inlining of the function naming/using in the official solution is harder to read, but that might be a personal preference. Here's my solution:

function reduce(arr, fn, initial) {
  function reduceWithCounter(counter, value) {
    if (counter > arr.length - 1) {
      return value;
    }

    return reduceWithCounter(counter + 1, fn(value, arr[counter], counter, arr));
  }

  return reduceWithCounter(0, initial);
}

@ghost
Copy link

ghost commented Nov 30, 2015

Hopping onto this issue with a similar feedback to what @kierans and @Monocotyledon said.

  1. Awesome workshop so far - really enjoy the format and challenges.
  2. When I arrived at Basic: Recursion, Exercise 7 of 18 - the directions kinda baffled me. I did not understand the part:

You don't need to implement this functionality, it will be supplied to your reduce implementation.

How or why the code I wrote from the previous exercise would be used exactly was mysterious, and compounded my difficulties to grasp recursion concepts.

  1. Finally, like @Monocotyledon said, the official solution I don't think I would have ever arrived at. A hint about IIFE or maybe a previous exercise involving them would help.

TL;DR - The conceptual leap between exercises 6 and 7 may be too great for JavaScript beginners. We need more direct instructions or additional clues about the solution.

@mrbalihai
Copy link

Just adding to the feedback about this issue. I've enjoyed the exercises so far but the official solution for this one looks a bit messy to me and isn't easy to follow due to the IIFE and the inlining. In the end I got the same solution as @Monocotyledon which I guess by using Array.prototype.slice isn't optimal. I would definitely have needed more pointers about maintaining the index in the recursion like @kierans said.

@LordJohn42
Copy link

Attention, spoiler. Official solution.

function reduce(arr, fn, initial) {
  return (function reduceOne(index, value) {
    if (index > arr.length - 1) return value // end condition
    return reduceOne(index + 1, fn(value, arr[index], index, arr)) // calculate & pass values to next step
  })(0, initial) // IIFE. kick off recursion with initial values
}

@ksorv
Copy link

ksorv commented Dec 10, 2018

@timoxley ah, true. We can increment the index, albeit at the expense of concision:

  // reduce `arr` with `reduction` method
  // initialize with `init`
  var reduce = function(arr, reduction, init) {
    var i, next, reduced;
    if (!arr.length) return init                        // nothing left to recur
    if (typeof i === "undefined" || i === null) i = 0   // increment index
    next = arr.shift();                                 // shift off first val
    reduced = reduction(init, next, i + 1, arr);        // get reduced value
    return reduce(arr, reduction, reduced);             // recur
  };

why are you passing arr in the last recursive step [return reduce...] and the function still working. If you do this your base condition shouldn't work.Right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants