Does condition expression of for loop changes after each iteration? - javascript

I'm trying to write a function decreasingOrder which takes a positive integer as input and return an array of its digits in decreasing order.
e.g., decreasingOrder(1234) Should give [4,3,2,1].
function decreasingOrder(n) {
let unarr = [...`${n}`].map(i => parseInt(i)); //Unordered Array of Digits
let oarr = []; //Ordered Array of Digits
for(let j=0; j<unarr.length; j++){
let max = Math.max.apply(Math, unarr);
oarr.push(max);
unarr.splice(unarr.indexOf(max), 1); //delete element from array
}
return oarr;
}
console.log(decreasingOrder(1234));
//Expected [4,3,2,1], Instead got [4,3]
I think, deleting element using splice method also reduces the number
of iteration.
I also tried delete operator but get [4, NaN, NaN, NaN] (because Math.max([undefined])).
When I tried with specific number instead of unarr.length in condition expression for for loop, it works fine!
So when I use splice method to delete elements it reduces the unarr.length and when I tried to keep unarr.length constant using delete operator it gives NaN, what should I do? Is there any other way to write to the same function? I'm beginner in JavaScript.

The issue in your code is unarr.splice(unarr.indexOf(max), 1) inside loop.
By taking your example of console.log(decreasingOrder(1234)). In the first cycle the highest number from the array is found and is removed from the array and pushed to new array.
At the end of the first cycle the outputs will be unarr = [1, 2, 3], oarr = [4] and j=1
Likewise after second loop unarr = [1, 2], oarr = [4, 3] and j=2. Now the loop condition j < unarr.length is not satisfied hence the loop breaks. So the output will be [4, 3].
Instead you can use the below utility for your requirement.
function decreasingOrder(n) {
let unarr = [...`${n}`].map(i => parseInt(i)) //Unordered Array of Digits
return unarr.sort((a,b) => b-a)
}
console.log(decreasingOrder(1234))
Hope this helps.

Related

Problem with getting javascript to forget a variables value

I'm trying to solve a coding challenge
it gives me an array and waits for the answer ,then gives me the next array and so on.
https://www.codewars.com/kata/5648b12ce68d9daa6b000099/train/javascript
I am trying to take this input: var busStops = [[10,0],[3,5],[5,8]] and return 5.
the code is supposed to add the first in each pair to a total while subtracting the second in each pair from the total eg: 10 - 0 + 3 - 5 + 5 - 8 = 5
First my code loops through the inner arrays and outer array ,pushing it into myarr as a regular array eg: [10,0,3,5,5,8].
It then adds the value if it is index is 0 or even and subtracts it if the index is odd.
This actually works!
Until it is given a second array eg: [[3,0],[9,1],[4,10],[12,2],[6,1],[7,10]]
It is still calculating the total correctly but is still remembering the total from the first array meaning it is returning 22 instead of 17
Why?
There is a var answer = 0 that is being executed ahead of the second loop
It should forget the value of the previous answer.
Right?
Edit: I figured out my problem. I just needed to empty myarr after the total was calculated!
let myarr = [];
var number = function (busStops) {
for (var i = 0; i < busStops.length; i++) {
for (var j = 0; j < busStops[i].length; j++) {
/*console.log(busStops[i][j]);*/
myarr.push(busStops[i][j]);
}
}
console.log("test");
var answer = 0;
console.log("test again");
for (let t = 0; t < myarr.length; t++) {
if (t == 0 || t % 2 == 0) {
answer = answer + myarr[t];
} else {
answer = answer - myarr[t];
}
}
console.log(answer);
return answer;
};
The task at your hand tries to somehow find a value (an integer) from an array of arrays (multidimensional array). That task seems to be reducing that multidimensional array into a single integer.
Luckily, JavaScript has some powerful array methods and one of them is the reduce method:
The reduce() method executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value. Source: MDN
The reduce method tries to reduce an array's elements into a single value and in your case we want to reduce that multidimensional array into a single value that is the number persons who are still in the bus.
Before typing some code, let's dig a bit deeper into the reduce method:
It accepts 2 parameters, a callback function that acts as the reducer and the initial value to be used in the first iteration of the reduce method.
The reducer callback function, on its own, accepts 4 parameters that are supplied by the reduce method. You may learn more about those parameters here as am only going to focus on the first 2 parameters the reducer accepts:
previousValue: hold the value from the previous reducer call. On first call, it contains the value you set to the initial value parameter of the reduce method or, if you didn't supply an initial value, previousValue shall hold the value of your array's first element (arr[0]).
currentValue: hold the current reduce iteration's item.
Now, let's get back to the task we have, we need to calculate the number of persons who are still in the bus based on a supplied multidimensional array. Each item in that multidimensional array is an array of two values where the result we need at the end is: the sum of the differences between each array, in the multidimensional array, first and second values (sum = multiDim[i][0] - multiDim[i][1] + multiDim[i + 1][0] + multiDim[i + 1][1] etc...).
To solve this task, we'll reduce that multidimensional array into a single number (let's call it result) by using a simple reducer function that will start by an initial value of 0 (as we're calculating a sum in our case) and will add, to the result, the difference between the first and the second values of the array supplied by the reduce at each iteration.
To illustrate, here's a live demo:
/**
* a function that calculates and returns the number of person who are still in the bus or precisely, the sum of the differences between "c[0]" and "c[1]"
* busArray: the supplied multidimensional array to reduce
* the reducer accepts two parameters:
* r: the result from the last call to the reducer function (initially set to 0, the initial value (see second parameter passed to the "reduce" method))
c: hold the current iteration's array.
*/
const calculateWhoAreInTheBus = busArray => busArray.reduce((r, c) => r += c[0] - c[1], 0);
/** test the created "calculateWhoAreInTheBus" function */
console.log(calculateWhoAreInTheBus([
[10, 0],
[3, 5],
[5, 8]
])); // should print: 5
console.log(calculateWhoAreInTheBus([
[3, 0],
[9, 1],
[4, 10],
[12, 2],
[6, 1],
[7, 10]
])); // should print: 17
console.log(calculateWhoAreInTheBus([
[3, 0],
[9, 1],
[4, 8],
[12, 2],
[6, 1],
[7, 8]
])); // should print: 21
console.log(calculateWhoAreInTheBus([
[0, 0],
[0, 0]
])); // should print: 0
I would advice you to use Array.prototype.reduce instead. For example like this:
const reducer = (previous, current) => previous + current[0] - current[1];
const answer = busStops.reduce(reducer, 0);
It is very brief (although this is not a goal in and of itself) and the reducer function does almost trivial work, so it does not complicate unneccesarily. Best of all it encapsulates the functionality with a minimal need of extra variables.
Othwerwise you could simplify your function a bit but use the let keyword to keep variables locked to scope like:
function number(busStops) {
let answer = 0;
for (let bs of busStops) {
answer += bs[0] - bs[1];
}
return answer;
}

Generating an array of arrays that when added equals a given number

i'm working on a bigger problem but am a little stuck on a certain issue. Hopefully, I can explain it clearly! I am looking to generate an array of arrays where each individual array has elements then when added together equal a certain number. An example would be:
target = 4
solution : [[1,1,1,1], [1,1,2], [2,2], [1,3], [4]]
edit: to make the question more clear, the solution should contain every possible combination of positive integers that will equal the target
You could take a recursive approach and loop from the last found item or one and call the function until no more values are to disperse.
function x(count) {
function iter(left, right) {
if (!left) return result.push(right);
for (var i = right[right.length - 1] || 1; i <= left; i++)
iter(left - i, [...right, i]);
}
var result = []
iter(count, []);
return result;
}
x(4).map(a => console.log(...a));
I'm not sure what language you were working in. Also, it's general StackOverflow etiquette to show what you have already tried an what exact step you got stuck on. That said, here is some Python code that does what you want.
This problem is easy to solve as a recursive function. If you have some number n, the first number in a list of sums of n could be any number between 1 and n. Call that number i. Once it's picked, the rest of the list should sum to n - i. So just make a recursive function that adds up the results for all i's that are less than n and all the results for each of the solutions to n-i.
def get_sum_components(n):
# ignore negatives
if n <= 0:
raise ValueError("n must be a positive int")
# The only way to sum to 1 is [1]. This is the base case
if n == 1:
return [[1]]
results = []
# imagine that the first number in the list of sum components was i
for i in range(1, n):
remainder = n - i
# get_sum_components(remainder) will return a list of solutions for n-i
for result in get_sum_components(remainder):
# don't forget to add i back to the beginning so they sum to n
result = [i] + result
results.append(result)
# lastly, just the number itself is always an answer
results.append([n])
return results
print(get_sum_components(4))
# gives [[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]]
If you don't care about order, this will create some duplicates (like [1, 3], [3, 1]). It should be easy to filter those out, though. (Just sort all the lists and then use a dict/set to remove duplicates)

Can someone explain why the reduce function consoled the following numbers

I am new to Javascript and was learning the reduce function today and going through the examples in Mozzila Developer and I slightly modified one and it gave me a result which I can not comprehend (since I am very new). Can someone pls explain the result here and the "rules" behind it? Thanks
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(accumulator, currentValue) {
return accumulator + currentValue
});
console.log(flattened)
Answer: 0, 12, 34, 5
Because you didn't pass an initial value as the accumulator, the initial value here is the array [0, 1]. On each iteration, the operation accumulator + currentValue is performed and used as the new accumulator on the next iteration (or, as the entire return value of the .reduce, if on the last iteration).
On the first iteration, [0, 1] + [2, 3] results in "0,12,3". This is because when non-numbers are used with +, they are converted into primitives first, and when arrays are converted to primitives, each item is joined by a comma. So
[0, 1] + [2, 3]
// evaluates to
'0,1' + '2,3'
// evaluates to
'0,12,3'
On the next iteration:
'0,12,3' + [4, 5]
// evaluates to
'0,12,3' + '4,5'
// evaluates to
'0,12,34,5'
That's the last iteration, so the final result is '0,12,34,5'.
Note that there are no spaces - the array items are joined only by a comma, not by a comma and a space.
It because reduces method reduces the array to a single value.
In your case, you are adding the arrays([0,1], [2,3], [4,5]) which return a string
Hence, the accumulator is accumulating the sum of iterated currentValue.
Working:
the loop works in the following steps
accumulator = "0,1"
accumulator = "0,1" + "2,3"
accumulator = "0,1" + "2,3" + "4,5"
readable output = "0,1 2,3 4,5"
System Generated Output = "0,12,34,5"

Preventing a loop within a loop. How to reduce complexity

You have 2 arrays.
arrA is empty.
arrB is full of stuff (what it's full of doesnt matter, but assume it's huge).
When a user does a thing, an item is removed from arrB and that item is placed in arrA.
When a user does a different thing, it pulls items from arrA and puts it in arrB.
Is it possible to do this without having a loop within a loop?
Or to put it in computer science terminology:
Is it possible to do this with linear ( ϴ(n) ) time/space complexity?
Right now I have something that is at least ϴ(n*k)
(where n is the length of arrB, and k is the number of items passed to applyItems):
var arrA = [], arrB = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
function addToArray(arrayToAddTo, item){
if(arrayToAddTo.indexOf(item) === -1){
arrayToAddTo.push(item);
}
}
function removeFromArray(arrayToRemoveFrom, item){
var i = arrayToRemoveFrom.length;
var temp = [];
while(i--){
if(arrayToRemoveFrom[i] !== item){
temp.push(arrayToRemoveFrom[i]);
}
}
return temp;
}
function applyItems(arrayOfItems){
var i = arrayOfItems.length;
while(i--){
var current = arrayOfItems[i]
addToArray(arrA, current);
arrB = removeFromArray(arrB, current);
}
}
applyItems([0, 5, 3]);
console.log(arrA);
console.log(arrB);
applyItems works, but is not efficient.
Is it possible to decrease the time/space complexity here?
Based on my comment:
You can use native tools that will be way faster than manually looping. removeFromArray can use indexOf to get the position of the one to remove and then uses splice to remove it. Also you can work with reference instead of recreating the array every time.
with some other optimizations...
var arrA = [], arrB = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
function addToArray(item){
if(arrA.indexOf(item) === -1){
arrA.push(item);
}
}
function removeFromArray(item){
var index = arrB.indexOf(item);
if (index > -1) {
arrB.splice(index, 1);
}
}
function applyItems(arrayOfItems){
arrayOfItems.map(function(item) {
addToArray(item);
removeFromArray(item);
});
}
applyItems([0, 5, 3]);
console.log(arrA);
console.log(arrB);
Right now I have something that is at least ϴ(n*k)
You can make it O(n+k) by using an efficient lookup structure for arrayOfItems that does not require looping, but allows you to determine in O(1) whether an item should be swapped into the other array. With that, a single pass over arrB is enough.
Or if you sort your array and use binary search for the lookup, you will have O(log k * (n+k)). However if your array is finite and very small anyway, that hardly matters.
Also you should omit that indexOf test in addToArray. It seems to be established that no items are in both arrA and arrB (and your algorithm maintains that invariant), so you will not have to check for duplicates before pushing an item to the array.
Yes. Instead of making your own remove function, you can use splice().
So, instead of removeFromArray(arrB, current) you can just do arrB.splice(i, 1);. That will remove 1 element from index i.
You don't need to loop over every element to check if it matches the one you want - just use indexOf(). So you can do something like
var i = arrA.indexOf(item)

Javascript: Why array variable assignment is behaving differently inside and outside this function?

For the life of me, I just can't figure out what I'm doing wrong here.
I'm trying to use both the reduce and concat array methods to take all of the values of a 2d array and combine them into a single value (basically condense them into a single array and then sum them up).
The problem that I keep running into is that when I try to make a for/loop to concat each array element, the argument that I'm passing into the function is not being recognized as an array, thus my call to .concat() is failing. I've placed a console.log() at the beginning of the function to see if the element is being recognized as the first array element in the 2d array, and it's coming up as "1"(?).
I tried another test outside of the function, and it logs as the actual array element. What am I doing wrong here? code below:
var arrays = [[1, 2, 3], [4, 5], [6]];
var myArray = arrays[0]; // Test
console.log(myArray); // Test
var flatArray = arrays.reduce(function(arrays)
{
console.log(arrays[0]); // Test
for (var i = 0; i < arrays.length - 1; i++)
{
arrays[0].concat(arrays[i+1]);
}
return arrays;
});
console.log(flatArray);
This is the output that I keep getting:
Array [ 1, 2, 3 ]
1
TypeError: arrays[0].concat is not a function
It's almost seems like array is being converted to a number-type when inside the function...?
You have an error in your code here:
var flatArray = arrays.reduce(function(param) {})
that param will be an element of your arrays vector.
Check this https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
You are using .reduce() incorrectly and you don't even need to use it to flatten an array. You can just do this:
var flatArray = [].concat.apply([],arrays);
Working demo: http://jsfiddle.net/jfriend00/wfjyfp42/
To understand .reduce(), the callback you pass it gets four arguments (see MDN reference). The first two arguments are important in using .reduce() correctly:
callback(previousValue, currentValue, index, array)
The previousValue is the accumulated value so far in the reduction. The currentValue is the next element of the array that is being iterated. The last two arguments do not need to be used if not needed.
Your code is only using the previousValue so it is never looking at the next item in the array as passed in by .reduce().
You could make a solution work using .reduce() like this:
var flatArray = arrays.reduce(function(previousValue, currentValue) {
return previousValue.concat(currentValue);
}, []);
Working demo: http://jsfiddle.net/jfriend00/2doohfc5/
Reduce performs an operation on two elements.
var sum = [[1, 2, 3], [4, 5], [6]].reduce(function(a, b) {
return a.concat(b);
}).reduce(function(a, b) {
return a + b;
});

Categories