Combining two arrays of same size and returns sum

雨燕双飞 提交于 2019-12-23 05:06:05

问题


In Javascript (or any other programming language with a functional-like syntax), if I have two arrays of the same size, say a = [1,2,3,4] and b=[5,6,7,8], what is the most efficient way to have the following result: c=[6,8,10,12].

For now, I do:

a.map(function(x,i){ return x+b[i] })

but ideally I would like a solution that doesn't involve the use of indexes.


回答1:


ES5 array methods are great, but old for loops are faster.

var sum = Array(a.length);
for(var i=0; i<a.length; ++i)
  sum[i] = a[i] + b[i];



回答2:


Warning: @dangor's answer mutates one of the inputs which is pretty awful imo. My answer will give you your result without yielding side effects.

Babel demo — The code below is written using ES6. If you want the ES5 code, view the right-hand panel in the Babel REPL.


I would recommend a zip function first. This function will take two arrays and create an array of tuples.

// zip :: [a] -> [b] -> [(a,b)]
let zip = (xs, ys) => {
  let iter = (zs, [x, ...xs], [y, ...ys]) =>
    (!x || !y) ? zs : iter(zs.concat([[x,y]]), xs, ys)
  return iter([], xs, ys);
};

let a = [1,2,3,4];
let b = [5,6,7,8];

zip(a,b); //=> [[1,5], [2,6], [3,7], [4,8]]

Now you can use map on each tuple

zip(a,b).map(t => t[0] + t[1]);
//=> [6,8,10,12]

So that last bit looks a little nasty, but we can clean that up if we continue to build some more functional building blocks

If we notice, in our mapping function, all we're doing is summing the elements of the array. We can avoid being over-specific by creating functions to do this.

Let's first look at how we'd sum an array ...

[1,2,3,4].reduce((x, y) => x + y, 0); //=> 10

OK, so the first thing we can improve here is the closure. That function is simply an add function.

let add = (x,y) => x + y;
[1,2,3,4].reduce(add, 0); //=> 10

But how would we use this to improve our original code ?

// original code
zip(a,b).map(t => t[0] + t[1]);      //=> [6,8,10,12]

// improvement #1
zip(a,b).map(t => t.reduce(add, 0)); //=> [6,8,10,12]

OK, not much of an improvement yet, and it's not going to get better until we fix that reduce function. JavaScript forces us to call reduce using this notation: obj.reduce(fn, i). This order of arguments kinda sucks, so let's fix that

// improvement #2
let reduce = f => i => xs => xs.reduce(f, i);
zip(a,b).map(reduce(add)(0)); //=> [6,8,10,12]

Finally, instead of using reduce(add)(0) every time we wanted to sum an array, we could just define a sum function

// improvement #3
let sum = reduce(add)(0);
zip(a,b).map(sum); //=> [6,8,10,12]

All together now ...

let zip = (xs, ys) => {
  let iter = (zs, [x, ...xs], [y, ...ys]) =>
    (!x || !y) ? zs : iter(zs.concat([[x,y]]), xs, ys)
  return iter([], xs, ys);
};

let add = (x,y) => x + y;
let reduce = f => i => xs => xs.reduce(f, i);
let sum = reduce(add)(0);

let a = [1,2,3,4];
let b = [5,6,7,8];

let result = zip(a,b).map(sum);

console.log(result);
//=> [6,8,10,12]

Sure, this results in more overall code than other solutions, but the point of the exercise is that by the time you've arrived at your solution using this method, you have four functions that you can now repurpose for other code: zip, add, reduce, and sum are all quite versatile; all of which are total and pure.

Lastly, the use of these functions affords us a point-free solution which exhibits a much stronger declarative dialect than an imperative one.

I hope this has helped you see how you can assemble several smaller functions to achieve your goals — all without having to do silly things like resort to imperative for loops or surrendering to reckless side effects like mutating inputs.




回答3:


There's another shorter option using using Array.map():

a = [1,2,3,4];
b = [5,6,7,8];

var result = a.map(function(item){
  return item + b.shift();
})



回答4:


No indices? Don't know if this is more efficient than your original code, but you can make a couple of improvements to thecodeparadox's answer, which already assumes you don't need to keep the original arrays.

  1. use pop instead of shift (followed by a final reverse)
  2. use a loop instead of recursion

something like:

function doSum(a, b) {
  var sum = [];
  while (a.length) sum.push(a.pop() + b.pop());
  return sum.reverse();
}


来源:https://stackoverflow.com/questions/32019544/combining-two-arrays-of-same-size-and-returns-sum

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!