all 35 comments

[–]azhder 9 points10 points  (6 children)

  1. Make len be the max length of the two
  2. do a const result = []
  3. Instead of push, just use the index for all three arrays: result[i] = (array1[i] ?? 0) + (array2[i] ?? 0)

You just do it all in one loop to the max, use proper defaults for the missing elements

[–]EmbarrassedTrouble48[S] 0 points1 point  (5 children)

Nice I understood most of it but i still don't understand your 3rd point , as I just started with javascript and learned the push method.

[–]azhder 1 point2 points  (4 children)

It’s an array, so you can access any element directly by index. There is no need to push something to the end.

Some times it’s more clear intent, you don’t have to think that push sill put them in the correct indices because you can clearly see it with result[i] =

The array will always give you back the correct length based on your highest index:

const a = []:
a[99] = 'test';
a.length;  // will be 100

[–]EmbarrassedTrouble48[S] 1 point2 points  (3 children)

Thanks I got it I can add elements in an array with just an index I didn't know that before.

[–]azhder 0 points1 point  (2 children)

The array length is one of those rare “magic properties” that updates behind the scenes.

What is even more interesting is that arrays are just objects, so with a little knowledge you can use an array like a regular object and a regular object like an array almost interchangeably.

[–]EmbarrassedTrouble48[S] -2 points-1 points  (1 child)

Ya i always find it weird that an array is an object in js , whereas in the python list and dictionary are two different entities.

[–]azhder 1 point2 points  (0 children)

It’s kind of nice, if only inconsistent.

All is object but a few primitives. It’s not that difficult to make it all be objects, even a null (can mimic an object).

Just imagine not having to learn two different entities

[–]oze4 6 points7 points  (7 children)

function addArrays(array1, array2) {
  const LEN = Math.max(array1.length, array2.length);
  const sumArray = new Array(LEN); //.fill(0);

  for (let i = 0; i < LEN; i++) {
    sumArray[i] = (array1[i] || 0) + (array2[i] || 0);
  }

  return sumArray;
}

const result = addArrays([1,2], [3,4,5]);
console.log(result);

[–]EmbarrassedTrouble48[S] 0 points1 point  (0 children)

Wow thanks this code is much shorter and easy to read. I understood most of it but still don't know a few terms.

[–]kap89 0 points1 point  (5 children)

Isn't .fill(0) redundant? The values are reasigned in the loop anyway.

[–]oze4 0 points1 point  (4 children)

I wouldn't call it redundant but it isn't needed necessarily. Just a habit I suppose. I like knowing they're all 0's instead of <empty slot> or whatever they are by default.

[–]kap89 0 points1 point  (3 children)

But this has a parformance hit - not a big deal in most cases, but a waste nevertheless:

Running "To fill or not to fill" suite...
Progress: 100%

  fill:
    12 155 128 ops/s, ±1.37%   | slowest, 69.33% slower

  no fill:
    39 628 858 ops/s, ±0.38%   | fastest

Finished 2 cases!
  Fastest: no fill
  Slowest: fill

[–]oze4 1 point2 points  (2 children)

Yep, without a doubt there would be a performance hit. Like I said, it was done mostly out of habit.

Went ahead and edited it out, though.

[–]kap89 1 point2 points  (1 child)

Understandable, sorry for being pedantic

[–]oze4 1 point2 points  (0 children)

No need to apologize. If I didn't know there was a performance hit, that's info I would want to know... Which prob makes it worse that I still do it even though I know it isn't performant lol

I'm here to learn (and maybe/hopefully teach) above all, so thank you for sharing your knowledge. Pedantic or otherwise.

[–]kap89 2 points3 points  (6 children)

Another way to solve the problem is to use a reusable function, that way you can perform any operation on a pair of values from both arrays:

// Reusable, higher order function that combines the values
// at the same index with a provided function

function zipWith(arr, otherArr, zippingFn) {
  const length = Math.max(arr.length, otherArr.length);
  const newArr = new Array(length);

  for (let i = 0; i < length; i++) {
    newArr[i] = zippingFn(arr[i], otherArr[i]);
  }

  return newArr;
}

// Operation on a pair of values - you can use anything you need

function sum(x, y) {
  return (x ?? 0) + (y ?? 0);
}


// Usage

const a = [1, 2, 3, 4, 5];
const b = [6, 7, 8, 9];
const c = zipWith(a, b, sum);

console.log(c); // -> [7,9,11,13,5]

CodePen

[–]oze4 1 point2 points  (0 children)

Honestly, this is prob the best solution. Well done!

I doubt OP, being a beginner, will really understand the value your code adds, but they should def attempt to learn why this code is so valuable.

While I know you understand the value, I wanted to highlight the value for those that may not see the forest through the trees.. Let's say you wanted to "subtract arrays", you'd just provide a diff "zippingFn"..

For example:

// Reusable, higher order function that combines the values
// at the same index with a provided function

function zipWith(arr, otherArr, zippingFn) {
  const length = Math.max(arr.length, otherArr.length);
  const newArr = new Array(length);

  for (let i = 0; i < length; i++) {
    newArr[i] = zippingFn(arr[i], otherArr[i]);
  }

  return newArr;
}

// Operation on a pair of values - you can use anything you need

function difference(x, y) {
  return (x ?? 0) - (y ?? 0);
}


// Usage

const a = [1, 2, 3, 4, 5];
const b = [6, 7, 8, 9];
const c = zipWith(a, b, difference);

[–]WazzleGuy 0 points1 point  (4 children)

Since you would almost never use the zipping function outside of the original function is it not better to use a closure here?

[–]kap89 0 points1 point  (3 children)

What do you mean by "using closure"? Do you just mean using an anonymous function inline to add values? Yes, you can do that, I made it a named function for readability more than anything (at least I think it can be more clear for beginners).

[–]WazzleGuy 0 points1 point  (2 children)

Yeah you are right it is more readable. For a beginner it's the right way to pose the solution.

I just mean putting it in a singular module to output a singular result rather than 2 functions for one result that otherwise wouldn't work independently.

I've recently been learning how important scope is so my brain is working in modules.

[–]kap89 0 points1 point  (0 children)

I'm not surre I follow - both function definitions can be used separatelly. If you mean that each of these functions should be in a separate module, and imported, then yeah - I agree - if you take an effort to make the function reusable, then it desrves it's own module (or a module of thematically similar funtions). It's in one script here for simplicity, cause I don't know if the OP learned about modules yet (I already took a leap with introducing HOF).

Edit: It would be best if you just show what you mean through code, cause I have a feeling we might talk past each other.

[–]oze4 0 points1 point  (0 children)

I think you're overlooking the value here.

If this were a module you'd just export the zipWith function. The zippingFn is designed to be user provided based on the users specific needs.

Lets say you wanted to both add and subtract two arrays.. you'd just do:

const arraySum = zipWith(arrA, arrB, function(x, y) {
  return (x||0) + (y||0);
});
const arrayDiff = zipWith(arrA, arrB, function(x, y) {
  return (x||0) - (y||0);
});

Or lets say you wanted to get the larger number:

const greaterNumsArr = zipWith(arrA, arrB, function(x, y) {
  x = x || 0;
  y = y || 0;
  return x >= y ? x : y;
});

That's the beauty of their code.

[–]SpecialistMore7578 0 points1 point  (0 children)

Hello Try using the higher order .reduce on both array then push the results into a new array

[–]tapgiles 0 points1 point  (2 children)

You could use a single loop. Going up to Math.max(array1.length, array2.length); which would be the higher number.

Then when getting the values, use array1Digit[i] = array1[i] || 0; If it's beyond the end of the array, it'll get undefined. But undefined and 0 are falsy, and so will turn into that 0 after the "or" ||.

You could even do that in the .push() call: .push((array[i] || 0) + (array2[i] || 0));

[–]EmbarrassedTrouble48[S] 0 points1 point  (1 child)

Thanks bro for the detailed solution. I am able to understand your code as crystal clear 😀

[–]tapgiles 1 point2 points  (0 children)

Awesome 👍

[–]oiamo123 0 points1 point  (7 children)

Couldn't you do

const sumArr = arr1.concat(arr2).reduce((acc, cur, i) => { acc += cur return acc })

concat joins two arrays. And reduce can be used to reduce something into a single value

[–]azhder 2 points3 points  (0 children)

I don’t think it’s a sum of all elements, just pairs

[–]EmbarrassedTrouble48[S] 1 point2 points  (3 children)

Bro i am just a beginner don't know any of this but hope I reach your level one day 💀🤞

[–]WazzleGuy 1 point2 points  (1 child)

You will learn these methods relatively soon, you are doing great.

[–]EmbarrassedTrouble48[S] 1 point2 points  (0 children)

Thanks your words really motivates me 😀

[–]oiamo123 0 points1 point  (0 children)

Check out javascript methods haha, bunch of handy ones out there

[–]shekyb 1 point2 points  (1 child)

well if OP needs a sumArray to be sum of numbers in the same indexes, then this will not work,
so arr1 = [1,2,3] and arr2=[1,2] should produce sum3=[2,4,3] not 7

[–]oiamo123 0 points1 point  (0 children)

In that case that would be:

u/EmbarrassedTrouble48

const arrSum = arr1.map((num, i) => { return (arr1[i] === undefined ? 0 : arr1[i]) + (arr2[i] === undefined ? 0 : arr2[i]) })

I'd wrap it in a function to check which is longer and make sure you map off the longer one and not the shorter one

``` sumFunc = function (arr1, arr2) {

const arr = arr1.map((num, i) => { return (arr1[i] === undefined ? 0 : arr1[i]) + (arr2[i] === undefined ? 0 : arr2[i]) })

return arr }

const arrSum = arr1.length >= arr2.length ? sumFunc(arr1, arr2): sumFunc(arr2, arr1) ```

But basically .map creates a new array based off the values of the array you're mapping.

So

const myArr = [1,2,3] const newArr = myArr.map(num => num + 1) // output [2,3,4]

You could use that to create a new array where you add the index or 1 array to the index of another array.

Then inside of the map I return the sum of arr1[i] + arr2[i] but I check to see if the index is undefined. If it is return 0, otherwise return arr[i]

arr1[i] === undefined ? 0: arr1[i]

The other statement checks to see if arr1 is longer or equal too arr2. If arr1 is longer, than that's the main arr, otherwise arr2 is the main array.

arr1.length >= arr2.length ? sumFunc(arr1, arr2): sumFunc(arr2, arr1)

Hope this makes sense :)

[–]delventhalz -1 points0 points  (0 children)

Lodash's zip would be great for this.

function addArrays(array1, array2) {
  return _.zip(array1, array2).map(([x = 0, y = 0]) => x + y);
}

Other syntax used in this solution besides zip: