传递数学运算符作为参数

时间:2014-03-10 15:01:35

标签: javascript

我想在Javascript中编写一个函数,允许我传入一个数学运算符和一个整数列表,并为该列表中的每个项目应用运算符。

从总和来看,这就是我提出的:

function accumulate(list, operator){
    var sum = 0;
    for each(var item in list){
        sum = accumulator(sum, item);
    }
    print(sum);
}

测试此代码会产生以下错误:

var list = new Array();
list[0] = 1;
list[1] = 2;
list[2] = 3;
js> accumulate(list, +);
js: "<stdin>", line 9: syntax error
js: accumulate(list, +);
js: ..................^
js: "<stdin>", line 9: Compilation produced 1 syntax errors.

8 个答案:

答案 0 :(得分:28)

您不能将运算符作为参数传递,但可以传递函数:

function accumulate(list, accumulator){   // renamed parameter
    var sum = 0;
    for(var i = 0; i < list.length; i++){ // removed deprecated for…each loop
        sum = accumulator(sum, list[i]);
    }
    print(sum);
}

accumulate(list, function(a, b) { return a + b; });

这与Array.prototype.reduce函数的作用非常接近,但不完全一样。要模仿reduce的行为,你必须从list获取第一个元素并将其用作累加器的种子,而不是总是使用0:

function accumulate(list, accumulator, seed){
    var i = 0, len = list.length;
    var acc = arguments.length > 2 ? seed : list[i++];
    for(; i < len; i++){
        acc = accumulator(acc, list[i]);
    }
    print(acc);
}

这样,您可以计算list的乘积(您的方法将始终返回0):

accumulate(list, function(a, b) { return a * b; });

更新:如果您正在开发支持ECMAScript 2015 / ES6的新浏览器(或使用像Babel这样的转发器),您还可以使用'arrow function'语法来编写代码更紧凑:

accumulate(list, (a, b) => a * b);

答案 1 :(得分:23)

如果您计划执行的所有操作都是二进制操作,那么您可以执行此操作

var operations = {
    "+" : function (operand1, operand2) {
        return operand1 + operand2;
    },
    "-" : function (operand1, operand2) {
        return operand1 - operand2;
    },
    "*" : function (operand1, operand2) {
        return operand1 * operand2;
    }
};

function accumulate(list, operator) {
    return list.reduce(operations[operator]);
}

console.log(accumulate([1, 2, 3, 4], "+"));     // 10
console.log(accumulate([1, 2, 3, 4], "-"));     // -8
console.log(accumulate([1, 2, 3, 4], "*"));     // 24

答案 2 :(得分:4)

我认为你可以用几种不同的方式做到这一点,但我会建议你这样的事情:

var operatorFunction = {
    '+' : function(x, y) {
        return x + y;
    },
    '-' : function(x, y) {
        return x - y;
    },
    '*' : function(x, y) {
        return x * y;
    }
};

function accumul(list, neutral, operator) {
    var sum = neutral;
    list.forEach(function(item) {
        sum = operatorFunction[operator](sum, item);
    });
    return sum;
}

console.log(accumul([2, 3, 4], 0, '+'));
console.log(accumul([2, 3, 4], 0, '-'));
console.log(accumul([2, 3, 4], 1, '*'));
console.log(accumul([], 0, '+'));
console.log(accumul([], 1, '*'));

在上面的示例中,您只需要accumul([2, 3, 4], 0, '+');之类的内容来调用您的功能。 operatorFunction[operator]调用相应的运算符函数。

在命令行中使用node.js运行示例,提供:

$ node accumulate.js 
9
-9
24
0
1

如果数组为空,此版本也可以使用。如果列表为空,则无法使用list.reduce

答案 3 :(得分:2)

var list = { a: 3, b: 7, c: 5 }
var expression = (a) => a * 2;

function computeObject(list, bc){
    for(var x in list){
        list[x] = bc(list[x]);
        console.log(list[x]);
    }
}
computeObject(list, expression);

答案 4 :(得分:0)

我知道这是一个老问题。只需添加一些更多信息即可。

如果您经常使用运算符并且需要reduce结果(accumulate),则强烈建议开发不同的帮助程序,以便您可以快速使用任何输入形式来获取结果。

尽管使用reduce并非总是如此,但以下帮助程序将允许将数组的第一个元素作为default值传递:

reducer = (list, func) => list.slice(1).reduce(func, list.slice(0, 1).pop())

以上内容仍然具有function依赖性,因此您仍然需要声明用于包装目标operator的特定函数:

sum = list => reducer(list, (a, b) => a + b)
sum([1, 2, 3, 4, 5])

例如,然后您可以重新定义sum,因为您看到的新输入格式将向后兼容。在此示例中,使用新辅助程序flat(目前仍处于实验状态;已添加代码):

flat = (e) => Array.isArray(e) ? [].concat.apply([], e.map(flat)) : e

sum = (...list)  => reducer(flat(list), (a, b) => a + b)
mult = (...list) => reducer(flat(list), (a, b) => a * b)

sum([1, 2, 3, 4, 5])
sum(1, 2, 3, 4, 5)

mult([1, 2, 3, 4, 5])
mult(1, 2, 3, 4, 5)

然后,您也可以使用reducer(或任何可能会发现更有用的变体)来简化其他助手的定义。矩阵自定义运算符的最后一个示例(在本例中为functions):

zip  = (...lists) => lists[0].map((_l, i) => lists.map(list => list[i]))
dot_product = (a, b) => sum(zip(a, b).map(x => mult(x)))

mx_transpose = (mx) => zip.apply([], mx)
// the operator
mx_product = (m1, m2) =>
    m1.map(row => mx_transpose(m2).map(
         col => dot_product(row, col) ))
// the reducer
mx_multiply = (...mxs) => reducer(mxs, (done, mx) => mx_product(done, mx))

A = [[2, 3, 4],
     [1, 0, 0]]
B = [[0, 1000],
     [1,  100],
     [0,   10]]
C = [[2,   0],
     [0, 0.1]]

JSON.stringify(AB   = mx_product (A,  B))
JSON.stringify(ABC  = mx_product (AB, C))
JSON.stringify(ABC2 = mx_multiply(A, B, C))

答案 5 :(得分:0)

只需传递1或-1作为输入,然后在wh之后将所有项目与此相乘。

答案 6 :(得分:0)

使用柯里化可以做得相当不错:

const calculate = a => str => b => {switch(str) {
  case '+': return a + b
  case '-': return a - b
  case '/': return a / b
  case '*': return a * b
  default: return 'Invalid operation'
}}

const res = calculate(15)('*')(28)

console.log('15 * 28 =', res)

答案 7 :(得分:-4)

不幸的是,它不可能像你想要的那样做到这一点。我要做的是传入一个数字,并有一个if / then或switch / case来决定根据这个数字做什么