How to keep adding the base values in an array until condition is met?

Here’s my code:

let arr = [2, 5, 7, 9, 12, 14, 20];

let arr2 = [10, 50, 70, 80, 90, 120, 150];

let arr3 = [];

for (i = 0; i < arr.length; i++) {
  while (arr[i] < arr2[i]) {
    arr[i] += arr[i];
  }

  arr3.push(arr[i]);
}

console.log(arr3);

I need to add the base values in the first array elements as long as the first array element is smaller than the second array elements. But i end up doubling the values. I simply need to increment the values in the first array by the base values.

For example: I want:

2 + 2 = 4
4 + 2 = 6
6 + 2 = 8

as long as its less than 10.

so the result array should be: [8, 45, 63, 72, 84, 112, 140]

How to make that happen. I know I am missing something very simple here.

Isn’t there a simple way to do this? If I can just keep adding the initial value to the value until the last possible value is reached. What would be the simplest logic for it?

It doesn’t work right for:

arr = [0.01, 0.05, 0.1, 0.25, 1, 5, 10, 20, 100];
arr2 = [1.01, 2.05, 3.1, 4.25, 90, 55, 20, 60, 100];

Yes, my bad sorry. The result array should be the maximum value of each element less than the arr2 element. And the value should increment by itself. So if the value in arr is 10 and its corresponding arr2 value is 90, then the result value should be 80.

First of all, your values are doubling because you’re reassigning them. You probably wanted to do something like:

for (let i = 0; i < arr.length; i++) {
  let counter = arr[i];
  while (counter < arr2[i]) {
    counter += arr[i];
  }

  arr3.push(counter);
}

Now, secondly, even if you would have done it, this wouldn’t work either :slight_smile: because you will still do the last addition after comparing values. You might do a little trick:

for (let i = 0; i < arr.length; i++) {
  let counter = arr[i];
  while (counter < arr2[i]) {
    counter += arr[i];
  }

  arr3.push(counter - arr[i]); //Here's the trick
}

or, something like this, which is slightly more readable:

for (let i = 0; i < arr.length; i++) {
  let counter = arr[i];
  while (counter + arr[i] < arr2[i]) {
    counter += arr[i];
  }

  arr3.push(counter);
}

Cheers

If you return to this problem later on you may be interested to know that an operation on two lists like this is known as a zip or zipWith in other languages

It’s a nifty generalisation, but it’s not important to know or anything, just thought you might find it interesting

You can imagine it as taking a pair of lists, creating a list of pairs, and then reducing over the list of pairs

Edit: changed map to reduce, though more precisely it’s a scan

It’s interesting to me how much shorter your solution could be with fractional data types freely available

The edge case where these numbers become too large for this kind of treatment would be irrelevant with fractional numbers based on the bigint proposal

@camperextraordinaire, first of all, this is @umairhp’s code. I just pointed out how to make his code work.
Secondly, it’s not the code that doesn’t account for rounding errors, it’s the way language works itself. It’s like saying that const add = (x, y) => x + y; is wrong, because add(.1, .2) doesn’t work :smile:

Now, if you want to discuss my code, discuss this ‘unreadable gibberish’:

const solveUmairhpProblem = (arr1, arr2) => arr1.map((n, i) => n >= arr2[i] ? n : arr2[i] % n ? arr2[i] - arr2[i] % n : arr2[i] - n);

Where did that come from?

Seems like you took a lot of offence where none was intended.

Alrighty then I guess I will take a look at your ‘unreadable gibberish’ if nobody else gets there first

const solveUmairhpProblem = (arr1, arr2) => arr1.map((n, i) => arr2[i] % n ? arr2[i] - arr2[i] % n : arr2[i] - n);

  • arr2[i] - arr2[i] can be simplified to 0 - is this what you want?
  • A map is the wrong abstraction when considering multiple arrays
  • Using the index with a map is bad form and should probably not have been allowed in the standard

If you intended to find arr2[i] - arr1[i] consider that arr2[i] - arr1[i] doesn’t work for 10 and 0.3, and also consider the fact that you have n already and don’t need to index arr1

I might have created some confusion given how many posts are here. I was replying to ‘doubling’ problem in the first post. And by saying ‘to make it work’ I clearly meant this “I simply need to increment the values in the first array by the base values.”

Com’on @gebulmer, no one makes an offensive post with smiles :slight_smile:
The ‘unreadable gibberish’ was addressed to @camperextraordinaire only, he knows why

Thanks for the feedback.

  1. I’m not sure JS would do negation before modulo, so arr2[i] - arr2[i] unfortunately is not a case here.
  2. What’s wrong about mapping item of the array to the item of another array?
  3. What??? How come? :slight_smile:

for (1) I misread the line as it was quite dense, my bad! :sweat_smile:

It’s not clear to me what (float) % (float) is meant to mean anyway, but JS is weird!

(2) and (3) are really down to the same thing, interpretation of what a map should be

In many languages, especially functional ones, (of which javascript is one in disguise!) a map refers to using a pure function that uses only the element of a list it’s currently operating on with no side effects

It makes reasoning about things that happen to large lists very easy, all you need to do is look at the function, think about what it does to a single (number/list/whatever) and you know what the final list looks like.

There’s also room with pure maps (of which JS can’t guarantee :frowning: )for some really cool optimisations where the array can be operated on in parallel and things like that

reduce or fold as it’s known elsewhere is an incredible tool - I won’t spoil how but it’s more general than the rest of these, and the rest of these can be implemented with it (and it’s still pure)

forEach is the abstraction that’s like map that’s associated with impure side effects such as mutation

The following should be in JS and aren’t:

zip is the abstraction that takes two lists and combines them to a list of pairs which can later be merged together

zipWith is the abstraction that takes two lists, examines the elements of each list together and calls a function of two variables on their elements

Note that zipWith is like a map over two arrays at once with a function of two variables

I’m not sure I got the part about map side effects and unpurity…

const arr1 = [1, 2, 3];
const arr2 = [5, 6, 7];
const mapIt = (arr1, arr2) => arr1.map((n, i) => n + arr2[i]);
const arr3 = mapIt(arr1, arr2);
arr3.pop();
console.log(arr1);
console.log(arr2);
console.log(arr3);
console.log(arr1 === arr3);
console.log(arr2 === arr3);

It’s a conceptual difference that comes from functional programming

A pure function doesn’t depend on the environment or state, and returns the same thing each time

The function

const f = function(x) {
     return arr2[x];
}

depends on the values of arr2 at the given time its called and doesn’t return the same value each time it’s called

The common use of map as an abstraction is to use map(f) where f is some pure function, operating over a collection


I’m not very good at explaining things which is probably why I’m not a teacher - I don’t think I can do a very good job of explaining why this is a good idea or why having both map and forEach and why they ought to be treated differently is important


If my next reply is slow I’ve fallen asleep, it’s 2:30am and I’ve polished off a bottle of wine

Wow. I didn’t expect so much debate on this. I was able to do it like this:

let arr = [2, 5, 7, 9, 12, 14, 20];

let arr2 = [10, 50, 70, 80, 90, 120, 150];

let arr3 = arr.slice();
console.log(arr3);

let arr4 = [];

for (var i = 0; i < arr.length; i++) {
while (arr[i] < (arr2[i] - arr3[i])) {
  arr[i] = arr[i] + arr3[i];
}

arr4.push(arr[i]);
}

console.log(arr4);