2
function each(coll, f) {
  if (Array.isArray(coll)) {
    for (var i = 0; i < coll.length; i++) {
      f(coll[i], i);
    }
  } else {
    for (var key in coll) {
      f(coll[key], key);
    }
  }
}

function map(array, f) {
  var acc = [];
  each(array, function(element, i) {
    acc.push(f(element, i));
  });
  return acc;
}

function max(numbers) {
  var maximum = numbers[0];
  each(numbers,function(x){
    if(x>maximum){
      maximum = x;}
  });
  return maximum;
}

function maximums(arrays){
  return map(arrays, function(x){
    return max(arrays);
  })
}

maximums([1,2,3],[5,6,7])

I don't quite understand map. I wrote a maximum number in an array function with each and I want to implement that to map. I know I am not returning the right thing with return max(arrays) but I've also tried return max(arrays[x]) to make an emphasize that I want to iterate through the whole argument of arrays. return max(arrays) ==> [3,3,3], returns the largest number in one array 3 times which i dont understand why either.

heliu
  • 67
  • 10
  • Hmm why not just `var arrs = [[1,2,3],[5,6,7]], maxes = arrs.map(a => Math.max(...a)); console.log(maxes);`? – Redu Dec 08 '16 at 20:23
  • because this was class and i had to break down everything and make sure i understand the abstraction of it before i do it shorthand in the future :) – heliu Dec 08 '16 at 20:24
  • The above code is not a shorthand. In 2016, it's the abstraction you should be thought in the JS class for this job. But OK i got your point. – Redu Dec 08 '16 at 20:31

5 Answers5

2

You need to get max from x

function maximums(arrays) {
    return map(arrays, function (x) {
        return max(x);
        //         ^                         
    });
}

And call the function with an array of arrays

maximums([[1, 2, 3], [5, 6, 7]]);
//       ^                    ^

function each(coll, f) {
    if (Array.isArray(coll)) {
        for (var i = 0; i < coll.length; i++) {
            f(coll[i], i);
        }
    } else {
        for (var key in coll) {
            f(coll[key], key);
        }
    }
}

function map(array, f) {
    var acc = [];
    each(array, function (element, i) {
        acc.push(f(element, i));
    });
    return acc;
}

function max(numbers) {
    var maximum = numbers[0];
    each(numbers, function (x) {
        if (x > maximum) {
            maximum = x;
        }
    });
    return maximum;
}

function maximums(arrays) {
    return map(arrays, function (x) {
        return max(x);
    })
}

console.log(maximums([[1, 2, 3], [5, 6, 7]]));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • 1
    ugh return max(x) was what i had in the beginning. i just called the function wrong! thanks!! – heliu Dec 08 '16 at 19:46
2

Your code is based off of a bad building block (each) and therefore the rest of your code suffers the consequences. My answer will start you off with a better building block, reduce (aka foldLeft), and show you how to build up from there.

What you'll notice about this answer is that we break each function down into really simple pieces and then use higher-order functions to put everything together.

  • avoid use of each which limits us to side-affecting functions
  • no need to check for Array.isArray
  • no imperative style for-loops with mutable iterators, i
  • no need to check array .length property

I highly encourage you to step thru the evaluation of this code and see how all of the parts work. If you can get an understanding of how either of these programs work, you'll be well on your way to mastering some of most important fundamentals of functional programming: recursion, immutability, referential transparency, higher-order functions, currying, and function composition

ES6 offers arrow functions, destructuring assignment, and spread syntax which makes functional programs a breeze to write in JavaScript – tho it will feel quite different to read, at first. I'll offer pre-ES6 below this snippet.

Related: What do multiple arrow functions mean in JavaScript?

// reduce is your new, gold-standard building block
const reduce = f => y => ([x,...xs]) => {
  if (x === undefined)
    return y
  else
    return reduce (f) (f (y) (x)) (xs)
}

// derive map from reduce
const map = f => reduce (acc => x => [...acc, f(x)]) ([])

// get max of 2 numbers
const max = x => y => x > y ? x : y

// get max of a list of numbers
const maximum = reduce (max) (-Infinity)

// get each max of a list of a list of numbers
const maximums = map (maximum)

// see the result of your hard work
console.log(maximums ([ [ 1, 3, 2 ], [ 7, 5, 6 ] ]))
// => [ 3, 7 ]

If you're struggling with the code above, this code (below) is written in ES5 (more accurately, pre-ES6). The more familiar syntax might help you along while you're still cutting your teeth. It's more verbose in ES5 but it works (almost) identically.

// reduce is your new, gold-standard building block
function reduce (f) {
  return function (y) {
    return function (xs) {
      if (xs.length === 0)
        return y
      else
        return reduce (f) (f (y) (xs[0])) (xs.slice(1))
    }
  }
}

// derive map from reduce
function map (f) {
  return reduce (function (acc) {
    return function (x) {
      return acc.concat([ f(x) ])
    }
  }) ([])
}

// get max of 2 numbers
function max (x) {
  return function (y) {
    return x > y ? x : y
  }
}

// get max of a list of numbers
var maximum = reduce (max) (-Infinity);

// get each max of a list of a list of numbers
var maximums = map (maximum);

// see the result of your hard work
console.log(maximums ([ [ 1, 3, 2 ], [ 7, 5, 6 ] ]))
// => [ 3, 7 ]

Of course there are other fundamentals of functional programming, but this is certainly a good start


Still stuck?

reduce is inarguably the most sophisticated function in the programs above. If you're struggling with it, we can cheat a little bit to short-cut our understanding of the program. JavaScript offers a built-in Array.prototype.reduce which (almost) works the same. We could write our reduce using JavaScript's and get the rest for free !

Just one more thing. JavaScript's reduce expects a binary function but the rest of our program is expecting curried functions (sequences of unary functions). To get around that, we will first make a small uncurry combinator to fit everything together

// convert sequence of unary functions to a binary function
const uncurry = f => (x,y) => f (x) (y)

// we can cheat using JavaScript built-in reduce with uncurry
const reduce = f => y => xs => xs.reduce(uncurry(f), y)

// the rest stays the same !
// ...

// derive map from reduce
const map = f => reduce (acc => x => [...acc, f(x)]) ([])

// get max of 2 numbers
const max = x => y => x > y ? x : y

// get max of a list of numbers
const maximum = reduce (max) (-Infinity)

// get each max of a list of a list of numbers
const maximums = map (maximum)

// see the result of your hard work
console.log(maximums ([ [ 1, 3, 2 ], [ 7, 5, 6 ] ]))
// => [ 3, 7 ]

Extra credit 1

So I told you reduce is your Gold Standard building block. Aside from map, did you know that you can also use reduce to implement countless other functions? Some include: filter, find, some, every, keys, and entries.

Extra credit 2

Some functions mentioned in Extra Credit 1 should short-circuit when the final answer can be returned before the end of the array is reached. Which ones can be short-circuited? And how can we rewrite reduce to facilitate this early-exit behaviour?

Community
  • 1
  • 1
Mulan
  • 129,518
  • 31
  • 228
  • 259
0

Have you tried return max(x);? I think that might be what you are wanting. Also there is a Max() in javascript so you do not need to define it:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max

Alex G Rice
  • 1,561
  • 11
  • 16
  • I've tried return max(x) and it returns [undefined, undefined, undefined]. and i know about math.max. i'm just trying to learn how to use map in different ways – heliu Dec 08 '16 at 19:44
  • wait youre right. i need to call it in a single array. smhhhh – heliu Dec 08 '16 at 19:45
  • 1
    > The map() method creates a new array with the results of calling a provided function on every element in this array. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map Hope that helps :) – Alex G Rice Dec 08 '16 at 19:46
0

You don't need to roll your own implementation for most of these functions. Use Math.max in conjunction with Array#map like this:

function maximum (array) {
    return Math.max.apply(null, array)
}

console.log(
    [[1,2,3], [5,6,7]].map(maximum)
) //=> [3, 7]
    
// if you still want a `maximums` function
function maximums (arrays) {
    return arrays.map(maximum)
}

console.log(
    maximums([[1,2,3], [5,6,7]]))
) //=> [3, 7]
gyre
  • 16,369
  • 3
  • 37
  • 47
0

You can combine map and reduce functions:

function maximums(x) {
    return x.map(function(y){
        return y.reduce(function(a,b){ return Math.max(a,b); });
    });
}