【问题标题】:Return the maximum number in each array using map使用 map 返回每个数组中的最大数
【发布时间】:2017-04-24 04:00:03
【问题描述】:
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])

我不太了解地图。我在每个数组函数中写了一个最大数,我想实现它来映射。我知道我没有用 return max(arrays) 返回正确的东西,但我也尝试过 return max(arrays[x]) 来强调我想遍历数组的整个参数。 return max(arrays) ==> [3,3,3],返回一个数组中的最大数 3 次,我也不明白为什么。

【问题讨论】:

  • 嗯,为什么不直接var arrs = [[1,2,3],[5,6,7]], maxes = arrs.map(a =&gt; Math.max(...a)); console.log(maxes);
  • 因为这是类,我必须分解所有内容并确保我理解它的抽象,然后才能在将来简写它:)
  • 以上代码不是简写。在 2016 年,这是您应该在 JS 类中为这项工作考虑的抽象。但好吧,我明白你的意思了。

标签: javascript arrays dictionary functional-programming higher-order-functions


【解决方案1】:

您的代码基于错误的构建块 (each),因此您的其余代码将承担后果。我的回答将从一个更好的构建块 reduce(又名 foldLeft)开始,然后向您展示如何从那里开始构建。

你会注意到这个答案是我们将每个函数分解成非常简单的部分,然后使用higher-order functions 将所有内容放在一起。

  • 避免使用each,这会限制我们使用副作用函数
  • 无需检查Array.isArray
  • 没有命令式风格for-带有可变迭代器的循环,i
  • 无需检查数组.length属性

我强烈建议您逐步评估此代码并了解所有部分的工作原理。如果你能理解这些程序是如何工作的,你就会很好地掌握函数式编程的一些最重要的基础知识:recursionimmutabilityreferential transparencyhigher-order functions、@ 987654326@ 和 function composition

ES6 提供了arrow functionsdestructuring assignmentspread syntax,这使得用 JavaScript 编写函数式程序变得轻而易举——虽然一开始读起来感觉完全不同。我会在这个 sn-p 下面提供 pre-ES6。

相关: 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 ]

如果您对上面的代码感到困惑,这段代码(下面)是用 ES5(更准确地说,是 ES6 之前的)编写的。当你还在磨牙时,更熟悉的语法可能会帮助你。它在 ES5 中更加冗长,但它的工作方式(几乎)相同。

// 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 ]

当然还有其他的函数式编程基础,但这无疑是一个好的开始


还是卡住了?

reduce 无疑是上述程序中最复杂的函数。如果您对此感到困惑,我们可以稍微作弊,以缩短我们对程序的理解。 JavaScript 提供了一个内置的Array.prototype.reduce,它(几乎)工作方式相同。我们可以使用 JavaScript 编写我们的reduce 并免费获得其余部分!

还有一件事。 JavaScript 的 reduce 需要 binary function,但我们程序的其余部分需要 curried 函数(unary functions 的序列)。为了解决这个问题,我们将首先制作一个小的 uncurry combinator 以将所有内容组合在一起

// 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 ]

额外积分 1

所以我告诉过你reduce 是你的黄金标准 基石。除了map,你知道reduce 还可以实现无数其他功能吗?其中包括:filterfindsomeeverykeysentries

额外积分 2

Extra Credit 1 中提到的一些函数应该short-circuit 在到达数组末尾之前返回最终答案时。哪些可以短路?我们如何重写reduce 来促进这种提前​​退出行为?

【讨论】:

    【解决方案2】:

    您可以组合mapreduce 函数:

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

    【讨论】:

      【解决方案3】:

      您不需要为大多数这些功能推出自己的实现。将Math.maxArray#map 结合使用,如下所示:

      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]

      【讨论】:

        【解决方案4】:

        你需要从x获得最大值

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

        并使用数组数组调用函数

        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]]));

        【讨论】:

        • ugh return max(x) 是我一开始所拥有的。我只是调用了错误的函数!谢谢!!
        【解决方案5】:

        你试过return max(x);吗?我认为这可能是你想要的。 javascript 中还有一个 Max(),所以你不需要定义它:

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

        【讨论】:

        • 我试过 return max(x) 并返回 [undefined, undefined, undefined]。我知道math.max。我只是想学习如何以不同的方式使用地图
        • 等你说得对。我需要在一个数组中调用它。嘘
        • > map() 方法创建一个新数组,其结果是对该数组中的每个元素调用提供的函数。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…希望有帮助:)
        猜你喜欢
        • 2018-10-01
        • 2014-04-13
        • 2015-11-03
        • 2019-06-09
        • 2021-08-09
        • 2018-03-30
        • 2017-11-27
        • 1970-01-01
        相关资源
        最近更新 更多