I just signed up in codewars and I'm trying the first kata. This is the question:
Write a function to multiply a number (x) by a given number (y) a certain number of times (n). The results are to be returned in an array.
eg.
multiplyBy(2, 4, 6);
The output is: [8, 32, 128, 512, 2048, 8192]
I believe my code is write, when I do console.log I get the array that the exercise is asking for, but it won't let me proceed. I'd appreciate some help, thanks!
var array = [];
function multiplyBy(x, y, n) {
while (x<2049){
var z = x*y*n;
var x = z;
array.push(z)
}
}
multiplyBy(2,2,2);
console.log(array);
return array;
You have a few things going on outside your function which make it only work one time. Make sure that you keep everything inside the function until the last return
function multiplyBy(x, y, n) {
var array = []; // var this inside your function
for (; n > 0; --n) { // the loop is only supposed to happen n times
x = x * y; // you can reuse this variable (x)
array.push(x);
}
return array; // return statement should be inside your function
}
// example of logging the returned value
console.log(multiplyBy(2, 4, 6)); // [8, 32, 128, 512, 2048, 8192]
Your while loop also was hardcoded to x<2049, but this isn't always the case as it depends on the n parameter given to the function
it won't let me proceed
There are 3 issues in the code you posted that probably prevent you from proceeding,
The return array is probably throwing a syntax error because it's outside a function
In your code, calling multiplyBy several times appends the new values onto the end of the previous array
They are probably testing your function against other sets of values to check it works as expected, which is not true in your function, i.e. you gave the example inputs of 2, 4, 6 but used 2, 2, 2 in your own code
As a final note, try to get into the habbit of indenting your code, it'll save you headaches reading it later as it lets you quickly see where blocks begin and end
Your return is outside the function. And all calls to multiplyBy populate the same array. And your logic is flawed.
Probably, it should be
function multiplyBy(x, y, n) {
var array = [];
while (n--) array.push(x *= y)
return array;
}
console.log(multiplyBy(2,4,6));
Or, in ECMAScript 6,
var multiplyBy = (x, y, n) => Array(n).fill().map(a => x*=y);
ramove the return at the end, this must be used in function to return something, if not used the function will return undefined.
Look at this (single-line solution):
function multiplyBy(x,y,n) {
return Array.apply(null, new Array(n)).map(function(v, i) { return x * Math.pow(y, i + 1); });
}
DEMO
Related
Don't understand why I have to make the assignment on line 28 to make the code work! Lines 17 to 21 is where I get the results.This is a very basic solution - more interested in why the code works.
//Given a list of non-negative integers and a target sum, find a pair of numbers that sums to the target sum.
function findPairForSum(integers, target)
{
// your solution here
var integerPairArray = [];
// first have the first element as one of the pairs
var firstInteger = integers[0];
// will store the sum of integers
var sum = 0;
// iterate through the remaining elements
for(var index = 1; index < integers.length; index++)
{
// add each to the first element and compare the result with the target
sum = firstInteger + integers[index];
// if true then return the pair in an array
if(sum === target)
{
integerPairArray.push(firstInteger, integers[index]);
break;
}
// if the end of the array is reached and there is no result
if(index === integers.length - 1 && sum !== target)
{
// remove the first element from the array
integers.shift();
// repeat the loop
integerPairArray = findPairForSum(integers, target);
}
}
return integerPairArray;
}
// example
var pair = findPairForSum([3, 34, 4, 12, 5, 2], 17);
console.log(pair); // --> [12, 5]
Since the question has comments, and no answers, I will endeavor to provide an answer based on the comments made .#Solomon P Byer really helped me understand my code! Thank you!
The final return statement from the findPairForSum(integers, target) declaration will go to this function call/expression - var pair = findPairForSum([3, 34, 4, 12, 5, 2], 17); - made outside the function.
Because I made a recursive call within the findPairForSum(integers, target) function, the final return statement will initially go to the call within the function. And because it is a return statement, it has to be ‘caught’ as #Solomon P Byer mentioned.
It is caught by the integerPairArray variable and then the final return statement in the function returns the answer to the function call made outside the function and we get the answer! Whew!
I have a CSV file of some data and for each line, I split it by the comma to get an array vals.
Now I want to pass vals into a function, but "flatten" it (without changing the function because it is used elsewhere)
function foo(x, y, z) {
return x*y*z:
}
var vals = [1, 3, 4];
//want a shortcut to this (this would be a nightmare with like 20 values)
foo(vals[0], vals[1], vals[2]);
Edit:
Sorry, kind of left out a big detail. I only want part of the array, like the first 10 elements of a 12 element array. Any shortcut for this?
Use Spread operator; if you are using es6.
var vals = [1,2,34,5]
foo(...vals)
Or you could also use apply
function foo(a,b,c,d,e) {
console.log(a,b,c,d,e)
}
var vals = [1,2,3,4,5]
foo.apply(null, vals)
first you don't need var in the parameters,
second, you may use the spread operator
function foo(x, y, z) {
return x * y * z;
}
var vals = [1, 3, 4];
console.log(foo(...vals));
reference: spread operator
I'm making a puzzle game that relies on elements being placed in grids and evaluating the values at certain x,y locations. My data is stored in 2d arrays, so regular maps don't work that well. As a result, I made this helper function to map over every single cell in a 2d array.
// makes transformations on the cell level in a 2d array
export const twoDMap = (twoDimensionalArray, mapFunction) => {
return twoDimensionalArray.map((row, y) => {
return row.map(mapFunction);
})
}
This works fine most of the time, except when I need to use the x,y indexes of a cell in my 2d map. In the test case below, I can't seem to access the y value of the cells. (I got rid of the ES6 syntax so it'll run in the console)
var testArray = [[true, "random-string", 3],
["potato", false, 4],
[null, 4, 5]];
function twoDMap(twoDimensionalArray, mapFunction) {
return twoDimensionalArray.map(function (row, y) {
return row.map(mapFunction);
})
}
function logCells(cells) {
twoDMap(cells ,function(cell, x) {
console.log(cell, "location: ", x);
// console.log(cell, "location: ", x, y); //throws an error
})
}
logCells(testArray);
I'm pretty sure I need to make some kind of change to twoDMap, and it's probably quite minor, but I've been on this problem for hours and still can't get it to work. When I write it out manually (using regular nested maps instead of twoDMap ), it works fine, but it's overly verbose and I'd like to avoid it considering that it's a common pattern in this project. This is the common suggestion that I keep finding whenever I google this problem, but it's not a viable solution given how much nesting I need to do for this project.
Essentially, I'm looking for a way to modify twoDMap or the callbacks that are sent into it, so that my callbacks can access the x and y indexes of the 2d array sent to twoDMap.
The issue is that the 'y' is out of scope to the current function, so it can't 'see' the value. For this reason you need to work out how to make it available to the second function. The two approaches I see:
Make second function's map an inner operation, within twoDimensionalArray.map(function (row, y)
Find a way to pass 'y' to the second function
For the first approach:
var testArray = [[true, "random-string", 3],
["potato", false, 4],
[null, 4, 5]];
function twoDMap(twoDimensionalArray) {
return twoDimensionalArray.map(function (row, y) {
return row.map(function (row, x) {
console.log(cell, "location: ", x, y);
}
})
}
twoDMap(testArray);
Below takes the second approach, using the bind() function:
var testArray = [[true, "random-string", 3],
["potato", false, 4],
[null, 4, 5]];
function twoDMap(twoDimensionalArray, mapFunction) {
return twoDimensionalArray.map(function (row, y) {
return row.map(mapFunction.bind(this, y);
})
}
function logCells(cells) {
twoDMap(cells , function(y, cell, x) {
console.log(cell, "location: ", x, y);
})
}
logCells(testArray);
When binding a values to a function always remember the first parameter should correspond to how you wish to define this and then the subsequent parameters are provided as initial parameters to the function you are calling.
I should add that sometimes using the traditional for loops makes for more manageable code, and sometimes benefit from better performance. An alternative, using for loops:
var testArray = [[true, "random-string", 3],
["potato", false, 4],
[null, 4, 5]];
function twoDMap(twoDimensionalArray) {
for (var y=0; y<twoDimensionalArray.length; y++) {
for (var x=0; x<twoDimensionalArray[y].length; x++) {
console.log(twoDimensionalArray[y][x], "location: ", x, y);
}
}
}
twoDMap(testArray);
Turns out, re-implementing the inner map as a for loop and then manually passing the coordinates to the transforming callback does the trick. The callback in array.map has to follow a set format for its arguments ( callback(element, index, array)) but by having the callback act alone in a for loop, that restriction is lifted.
var testArray = [[true, "random-string", 3],
["potato", false, 4],
[null, 4, 5]];
function twoDMap(twoDimensionalArray, transform) {
return twoDimensionalArray.map(function (row, y) {
var mapped = [];
for (var x = 0; x < row.length; x++)
mapped.push(transform(row[x], x, y));
return mapped;
})
}
twoDMap(testArray, function(cell, x, y) {
console.log(cell, x, y);
})
if someone knows why the first attempt with the nested map didn't work, I'd be very curious to learn about that. I still don't know why it didn't have access to the scope that contained the y...
I'm trying to solve a freeCodeCamp exercise with this goal:
Write a function that takes two or more arrays and returns a new array
of unique values in the order of the original provided arrays.
In other words, all values present from all arrays should be included
in their original order, but with no duplicates in the final array.
The unique numbers should be sorted by their original order, but the
final array should not be sorted in numerical order.
So what I do is concatenate all the arguments into a single array called everything. I then search the array for duplicates, then search the arguments for these duplicates and .splice() them out.
So far everything works as expected, but the last number of the last argument does not get removed and I can't really figure out why.
Can anybody please point out what I'm doing wrong? Please keep in mind that I'm trying to learn, so obvious things probably won't be obvious to me and need to be pointed out. Thanks in advance.
function unite(arr1, arr2, arr3) {
var everything = [];
//concat all arrays except the first one
for(var x = 0; x < arguments.length; x++) {
for(var y = 0; y < arguments[x].length; y++) {
everything.push(arguments[x][y]);
}
}
//function that returns duplicates
function returnUnique(arr) {
return arr.reduce(function(dupes, val, i) {
if (arr.indexOf(val) !== i && dupes.indexOf(val) === -1) {
dupes.push(val);
}
return dupes;
}, []);
}
//return duplicates
var dupes = returnUnique(everything);
//remove duplicates from all arguments except the first one
for(var n = 1; n < arguments.length; n++) {
for(var m = 0; m < dupes.length; m++) {
if(arguments[n].hasOwnProperty(dupes[m])) {
arguments[n].splice(arguments[n].indexOf(dupes[m]), 1);
}
}
}
//return concatenation of the reduced arguments
return arr1.concat(arr2).concat(arr3);
}
//this returns [1, 3, 2, 5, 4, 2]
unite([1, 3, 2], [5, 2, 1, 4], [2, 1]);
Looks like you overcomplicated it a bit ;)
function unite() {
return [].concat.apply([], arguments).filter(function(elem, index, self) {
return self.indexOf(elem) === index;
});
}
res = unite([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]);
document.write('<pre>'+JSON.stringify(res));
Explanations
We split the problem into two steps:
combine arguments into one big array
remove non-unique elements from this big array
This part handles the first step:
[].concat.apply([], arguments)
The built-in method someArray.concat(array1, array2 etc) appends given arrays to the target. For example,
[1,2,3].concat([4,5],[6],[7,8]) == [1,2,3,4,5,6,7,8]
If our function had fixed arguments, we could call concat directly:
function unite(array1, array2, array3) {
var combined = [].concat(array1, array2, array3);
// or
var combined = array1.concat(array2, array3);
but as we don't know how many args we're going to receive, we have to use apply.
someFunction.apply(thisObject, [arg1, arg2, etc])
is the same as
thisObject.someFunction(arg1, arg2, etc)
so the above line
var combined = [].concat(array1, array2, array3);
can be written as
var combined = concat.apply([], [array1, array2, array3]);
or simply
var combined = concat.apply([], arguments);
where arguments is a special array-like object that contains all function arguments (actual parameters).
Actually, last two lines are not going to work, because concat isn't a plain function, it's a method of Array objects and therefore a member of Array.prototype structure. We have to tell the JS engine where to find concat. We can use Array.prototype directly:
var combined = Array.prototype.concat.apply([], arguments);
or create a new, unrelated, array object and pull concat from there:
var combined = [].concat.apply([], arguments);
This prototype method is slightly more efficient (since we're not creating a dummy object), but also more verbose.
Anyways, the first step is now complete. To eliminate duplicates, we use the following method:
combined.filter(function(elem, index) {
return combined.indexOf(elem) === index;
})
For explanations and alternatives see this post.
Finally, we get rid of the temporary variable (combined) and chain "combine" and "dedupe" calls together:
return [].concat.apply([], arguments).filter(function(elem, index, self) {
return self.indexOf(elem) === index;
});
using the 3rd argument ("this array") of filter because we don't have a variable anymore.
Simple, isn't it? ;) Let us know if you have questions.
Finally, a small exercise if you're interested:
Write combine and dedupe as separate functions. Create a function compose that takes two functions a and b and returns a new function that runs these functions in reverse order, so that compose(a,b)(argument) will be the same as b(a(argument)). Replace the above definition of unite with unite = compose(combine, dedupe) and make sure it works exactly the same.
You can also try this :
var Data = [[1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]]
var UniqueValues = []
for (var i = 0; i < Data.length; i++) {
UniqueValues = [...new Set(UniqueValues.concat(Data[i]))]
}
console.log(UniqueValues)
I am practicing solving problems with recursion for a class.
I am solving the problems on this site : http://www.w3resource.com/javascript-exercises/javascript-recursion-functions-exercises.php
The question I am referring to is stated : Write a JavaScript program to get the integers in range (x, y).
Example : range(2, 9)
Expected Output : [3, 4, 5, 6, 7, 8]
Before looking at the solution I came up with this:
var range = function (start, end) {
var result = [];
var accumulator = start;
var accumulate = function () {
accumulator++;
if (accumulator === end) {
return;
} else {
result.push(accumulator);
}
accumulate();
};
accumulate();
return result;
};
The solution on the site is this:
var range = function(start_num, end_num)
{
if (end_num - start_num === 2)
{
return [start_num + 1];
}
else
{
var list = range(start_num, end_num - 1);
list.push(end_num - 1);
return list;
}
};
Is my solution technically still recursive? I had a similar answer on a quiz recently and I was told my solution is essentially iterative.
Though you use recursion, you have simply written a loop in the form of recursion.
I am going to answer this from the purely academical standpoint. If you want to avoid the intermediate state (result) and use purely functional constructs, I would write it like this
function range(start, end) {
function recRange(current, end) {
if (current > end)
return [];
return [current].concat(recRange(current + 1, end));
}
return recRange(start + 1, end - 1);
}
console.log(range(2, 9));
// [ 3, 4, 5, 6, 7, 8 ]
If you see here, we create a new function within the range function, which recursively creates a new array on every iteration (remember: this is not highly performant code, you can simply use loops and be done with this problem efficiently).
The base condition of the recursion is current < end. Once that is met, the recursion stops and an empty array is returned. In all the levels, a new array with the current value is concatenated with the result of the recursive call. So, the evaluation of the calls are roughly understood like this
[3].concat(recRange(3 + 1, end));
[3].concat([4].concat(recRange(4 + 1, end)));
...
at the end, when the recursion unwinds, the values will be like this
[3].concat([4].concat([5].concat([6].concat([7].concat([8].concat([]))))))
[3].concat([4].concat([5].concat([6].concat([7].concat([8])))))
[3].concat([4].concat([5].concat([6].concat([7, 8]))))
[3].concat([4].concat([5].concat([6, 7, 8])))
[3].concat([4].concat([5, 6, 7, 8]))
[3].concat([4, 5, 6, 7, 8])
[3, 4, 5, 6, 7, 8]
and that will be returned as the result.
To make your solution recursive, it should return some value and somehow combine the result of the recursive call to form the return value of the original call.
Let me illustrate that with an example, by modifying your solution:
var range = function (start, end) {
var accumulate = function (accumulator) {
if (accumulator === end - 1) {
return [accumulator]; // Stop condition
} else {
// Recursive block
var result = accumulate(accumulator+1); // recursive call
result.unshift(accumulator); // combine result
return result
}
};
return accumulate(start);
};
The modified accumulate function will return a one-element list for the stop condition, the simplest case it handles, where accumulator reaches the last value to return.
In the example range(2,9), the stop condition will return [8].
Then in the caller, the recursive block
var result = accumulate(accumulator+1);
result.unshift(accumulator);
return result
will take the list [8], and preprend the current value of accumulator (7), so it'll return [7,8].
...and the caller of accumulator(7), will receive [7,8] and preprend the value 6 to the list, to return [6,7,8].
At the end, the original call to accumulator(2) will generate the expected result [2,3,4,5,6,7,8].
Is my solution technically still recursive?
Yes. You're using tail recursion; however, since no arguments are being passed to accumulate() I can see why someone may say it's essentially iterative. You could easily replace your recursive call with a loop. Recursive algorithms typically leverage the stack.
Because of Javascript's closures, it is harder to understand the concept of recursion in Javascript compared to other languages like C++ or Java or C#.
To understand recursion, you must first understand recursion. :)