Related
My logic for the problem, using the below as the input.
var input = [['A','B'],1,2,3,['C','D']]
Check first element to see if is an Array or not using Array.isArray(input)
If first element is array, call function, first element ['A,'B'] as argument.
The first element of the nested array is 'A' which is not an array, so push this element into a result array, and shift this element out. Repeat the function call.
When trying to flatten nested arrays using recursion, my input variable to the function keeps getting reassigned, preventing me from calling the function again using the original array. How do I prevent the original input variable from getting reassigned?
I understand this is not the complete solution, however I am stuck at when I shift the first element out of the nested array.
I've gone through step by step with this function, but there must be something I'm missing, another set of eyes would help greatly.
I've also been using my chrome developer tool, set breakpoints to monitor the function step by step.
//Defining original input variable
var input = [['A','B'],1,2,3,['C','D']]
function flat(array){
var result = []
var firstElement = array[0]
//CHECK IF FIRST ELEMENT IS ARRAY OR NOT
if(Array.isArray(firstElement)){
return flat(firstElement)
}
//IF ELEMENT NOT ARRAY, PUSH ELEMENT TO RESULT
else{result.push(firstElement)
array.shift() //removing child element
return (flat(array)) //call function on same array
}
if(array.length===0){return result}
}
First iteration:
firstElement = ['A','B'], Array.isArray(firstElement) would be true, hence call flat(firstElement)
Second Iteration:
firstElement = 'A', Array.isArray(firstElement) is false, so we
1. jump down to push this element into result
2. remove 'A' by using array.shift()
3. Call flat(array), where array is now ['B']
Third Iteration:
firstElement = 'B', Array.isArray(firstElement) is false
1. jump down to push this element into result, result is now only ['B'] since I've reset the result when I recalled the function.
2. remove 'B' by using array.shift(), array is now empty, ->[ ]
3. How can I step out, and use flat() on the original input array?
Your code doesn't consider the following elements if the first element is an array. The solution below uses array.concat(...) to combine both the result of the recursion (going down the tree), but also to combine the results of processing the rest of the list (in the same level). Visualizing the problem as a tree, often helps with recursions IMO:
[] 1 2 3 []
| |
A [] C D
|
B C
So perhaps it is more clear here, that we must both concat the result of the recursion and the result of taking a "step" to the right (recursion again) which would otherwise be a loop iterating the array.
var input = [['A',['B', 'C']],1,2,3,['C','D']]
function flat(array) {
var result = []
if (array.length == 0) return result;
if (Array.isArray(array[0])) {
result = result.concat(flat(array[0])); // Step down
} else {
result.push(array[0]);
}
result = result.concat(flat(array.slice(1))) // Step right
return result;
}
console.log(flat(input));
// ["A", "B", "C", 1, 2, 3, "C", "D"]
This is somewhat analogous to a version with loops:
function flat(array) {
var result = []
for (var i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) {
result = result.concat(flat(array[i]));
} else {
result.push(array[i]);
}
}
return result;
}
EDIT: For debugging purposes, you can track the depth to help get an overview of what happens where:
var input = [['A',['B', 'C']],1,2,3,['C','D']]
function flat(array, depth) {
var result = []
if (array.length == 0) return result;
if (Array.isArray(array[0])) {
result = result.concat(flat(array[0], depth + 1));
} else {
result.push(array[0]);
}
var res1 = flat(array.slice(1), depth);
console.log("Depth: " + depth + " | Concatenating: [" + result + "] with: [" + res1 + "]");
result = result.concat(res1)
return result;
}
console.log(flat(input, 0));
If you want to avoid loops, and I'm considering concating/spreading arrays as loops, you need to pass the result array to your function.
const input = [['A', 'B'], 1, 2, 3, ['C', 'D']]
// Start the function with an empty result array.
function flat(array, result = []) {
if (!array.length)
return result
// Extract first element.
const first = array.shift()
// Call the function with the array element and result array.
if (Array.isArray(first))
flat(first, result)
// Or add the non array element.
else
result.push(first)
// Call the function with the rest of the array and result array.
flat(array, result)
return result
}
console.log(flat(input))
Here is my answer if you are using JavaScript
You can use the below one line code to flatten n level nested Array
let flattendArray = input.flat(Infinity);
Or use this approach using reduce and concat
function flatDeep(arr, d = 1) {
return d > 0 ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatDeep(val, d - 1) : val), [])
: arr.slice();
};
Refer this link
I currently have a function that allows me to test if something a piece (for connect 4) is in an array, as well as 1, 2, and less respectively. If all 4 numbers are in the array are present, then it returns true. This works.
What I am trying to do is make it so I can use .some, so I can test if the array contains any cases of having a number, and again 3, 2, and 1 less than the number tested.
Right now it will test an individual piece, but I don't know how to get it to grab onto the array to check the index of the individual element it is testing.
Thank you for any responses/Ideas.
const testPieces = [1, 2, 3, 4]
const fourInARow = function(piece, array) {
for (var i = piece; i >= piece - 3; i--) {
if (array.indexOf(i) === -1) {
return false
}
}
return true
}
testPieces.some(fourInARow) // The piece that I don't know how to make work
Calling .some on your testPieces array will pass in each element of the array to the fourInARow function as the piece argument. It will not pass in your second array argument.
You need to provide a function to the .some call that already knows about the array for testing. You can do this by returning a function from the function e.g.
const fourInARow = function(array) {
return function(piece) {
for (var i = piece; i >= piece - 3; i--) {
if (array.indexOf(i) === -1) {
return false
}
}
return true
};
}
The array you are testing can now be passed to the .some call like this;
testPieces.some(fourInARow([1,2]));
The returned function has created a closure which retains a reference to the test array [1,2] which is then compared to the piece argument supplied by the call to .some.
Just wondering why not flip the logic to start from the other side and use instead of some every with includes?
const testPieces = [1, 2, 3, 4]
const inARow = (arr, base) => arr.every((x) => base.includes(x))
console.log(inARow([4,3,1,2], testPieces))
console.log(inARow([5,2,1], testPieces))
It becomes one line, it does not care about the order etc. Let me know if I am missing something ...
I hope this is not a repeated question-- though I couldn't find much help on this.
I am practicing recursive functions (I'm a newbie), and I'm trying to multiply each number in an array. Sort of like a factorial. I have this code, but it is only returning undefined as a result.
Here is the code:
var stack = [];
function countDown(int) {
stack.push(int);
if (int === 1) {
return 1;
}
return countDown(int - 1);
}
function multiplyEach() {
// Remove the last value of the stack
// and assign it to the variable int
int = stack.pop();
x = stack.length;
// Base case
if ( x === 0 ) {
return;
}
// Recursive case
else {
stack[int - 1] = int * stack[x - 1];
return multiplyEach(int);
}
}
// Call the function countDown(7)
countDown(7);
// And then print out the value returned by multiplyEach()
console.log(multiplyEach());
Thank you so much for any insight.
Cheers!
The first thing to address is that your multiplyEach() function should have a parameter named int, from the looks of it. The approach you're using might be better suited to a different technique, but we'll get to that.
Next, in multiplyEach(), there are two possible paths:
The stack still has elements, in which case we multiply the new top value on the stack by the old one and move on to another run of multiplyEach.
The stack is empty, and we just return.
The problem here is that we aren't actually returning the final stack value, or leaving it on there to access later. We've effectively lost it, so what is the function outputting?
In many languages, we would have defined a return type for this function, either void for no value, or int for returning the multiplied value. However, in Javascript, there is no such thing as a function that doesn't return a value; "nothing" in JS is represented as undefined. When you return multiplyEach(), you're pushing another call of it onto the call stack, and waiting for an actual return value... which ends up being return;, which JS interprets as return undefined;. Again, in most languages, there would be some form of error, but not in JS! Let's look at two possible implementations:
The custom stack you use:
// your stack is fine, so we'll skip to the meat
function multiplyEach() {
var int = stack.pop(), x = stack.length;
stack[x - 1] *= int;
if(x < 2) // to multiply, we need at least two numbers left
return;
multiplyEach();
}
//...
multiplyEach();
console.log(stack[0]);
With a parameter, and using a list:
function multiplyEach(index) {
var int = list[index];
if(index == 0)
return int;
return int * multiplyEach(index - 1);
}
//...
console.log(multiplyEach(list.length - 1));
They're both different ways of implementing this recursively; all recursion inherently requires is for a function to call itself. Another possibility would have been having a parameter store the total, instead of multiplying the return values like in option 2; that's called tail recursion.
EDIT: noticed the base case for option 1 was in the wrong place, so I moved it. It should work now.
Recursively you can do this way:
function multiplyEach(arr, size) {
return size === 0 ? arr[size] : arr[size] * multiplyEach(arr, size - 1);
}
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(multiplyEach(array, array.length - 1));
But you can do it using the native method reduce, then you could do simply this:
console.log([1, 2, 3, 4, 5, 6, 7, 8, 9].reduce(function(a, b) { return a * b; }));
ES6 version:
console.log([1, 2, 3, 4, 5, 6, 7, 8, 9].reduce((a, b) => a * b));
I hope it helps.
There are times recursion is better suited to solve a problem and there are times iteration is better suited to solve a problem.
Recursion is better suited for performing an action until a condition is met then exiting, similar to a while loop.
Iteration is better suited for performing an action N number of times then exiting, similar to a for loop.
In our case, we want to input an array and output the product of all elements of that array. In other word, we want to perform N - 1 multiplications where N is the number of elements in the array. Since we know the number of operations we want to perform we should solve our problem with iteration which is done below.
var arr = [1, 2, 3]
var result = multiplyEach(arr)
console.log(result)
// -> 6
function multiplyEach(arr) {
var result = 1
arr.map(function(value) {
result *= value
})
return result
}
Keep in mind though that the above is an approximate rule of thumb because sometimes recursion will be a more elegant solution than iteration. Here's the simple, recursive, and elegant implementation of the real factorial.
function factorial(value) {
return 1 === value ? 1 : value * factorial(value - 1)
}
The iterative implementation of factorial is not as pretty in while loop form nor for loop form.
function factorial(value) {
var result = 1
while (value > 0) {
result *= value
value--
}
return result
}
function factorial(value) {
var result = 1
for (var i = 0; i < value; i++) {
result *= value
}
return result
}
I think the main issue is that you do not have an argument in the multiplyEach() definition, but you attempt to call it with one inside the function.
Something like this works:
var stack = [1, 2, 3, 4, 5, 6, 7];
function multiplyEach(arr) {
if (arr.length == 0) {
return 1;
} else {
return arr.pop() * multiplyEach(arr);
}
}
console.log(multiplyEach(stack));
The base case in the recursive function multiplyEach() returns undefined.
That's where your problem lies.
A simple fix would be:
var stack = [];
var multipliedStack = [];
function countDown(int) {
stack.push(int);
if (int === 1) {
return 1;
}
return countDown(int - 1);
}
function multiplyEach() {
// Remove the last value of the stack
// and assign it to the variable int
int = stack.pop();
x = stack.length;
// Base case
if ( x === 0 ) {
return multipliedStack.reverse();
}
// Recursive case
else {
multipliedStack.push(int * stack[x - 1]);
return multiplyEach(int);
}
}
// Call the function countDown(7)
countDown(7);
// And then print out the value returned by multiplyEach()
console.log(multiplyEach());
I don't fully get what you mean by "sort of like a factorial"? What exactly is the function supposed to do?
To understand recursion you need to wrap your head around what a recursive base case is and also I think you need to revise push() and pop() which are not used in a proper way in your code.
Recursive functions are usually abit confusing if you are used to iteration, keep trying and you'll get comfortable with it rather quick.
I am trying to use the reduce method as follows to eliminate duplicates however, it is not quite working:
var unique = function(array) {
array = array.sort(function(a,b) {return a-b;});
var noDup = [array[0]];
array.reduce(function(c,d) {
if(c!==d) {
noDup.push(d);
return d;
}
});
return noDup;
};
var x = [9,2,1,5,9,1,1,4,2,9];//==>[1, 1, 2, 4, 5, 9, 9]
function unique(values) {
return values.reduce(function(prev, cur) {
if (prev.indexOf(cur) == -1) {
prev.push(cur);
}
return prev;
}, []);
}
unique([9,2,1,5,9,1,1,4,2,9]) // --> [9, 2, 1, 5, 4]
fiddle
You are using the "intermediate value" of reduce to hold the previous value, so you can check against it the next time through. But that leaves you with no way to calculate the real intermediate value you want, which is the unique array you are building, so you having to declare it outside (noDup), which sort of defeats the whole purpose. Then your code has issues such as not providing an initial value to reduce. In that case, reduce has a special behavior which is that it calls the callback with the first two values of the array; a situation you are not handling properly.
Anyway, since it seems you are willing to sort the array, you can avoid doing an indexOf each time through the loop, by just remembering the previous value and checking against it:
function unique(values) {
var prev;
return values . sort() . reduce(function(result, cur) {
if (cur !== prev) result.push(cur);
prev = cur;
return result;
}, []);
}
But it turns out actually we don't need to keep the value of prev; instead, we can simply refer to the previous element directly, since filter passes additional arguments of index and array to the callback, so:
function unique(values) {
return values . sort() . reduce(function(result, cur, index, array) {
if (cur !== array[index-1]) result.push(cur);
return result;
}, []);
}
But if you think about it, this is nothing more than a filter written using reduce. It's just filtering out numbers that are the same as the previous one. So just write it as a filter to start with:
function unique(values) {
return values . sort() . filter(value, i, arr) { return value !== arr[i-1]; });
}
There are other approaches to removing duplicates using filter which don't require the sort. Here's a simple one:
values . filter(function(value, i, arr) { return arr.indexOf(value) === i; });
What this says is, filter out a number if the location where it is first found in the array is its location. In other words, filter out numbers that occur earlier in the array.
I would like to filter an array of items by using the map() function. Here is a code snippet:
var filteredItems = items.map(function(item)
{
if( ...some condition... )
{
return item;
}
});
The problem is that filtered out items still uses space in the array and I would like to completely wipe them out.
Any idea?
EDIT: Thanks, I forgot about filter(), what I wanted is actually a filter() then a map().
EDIT2: Thanks for pointing that map() and filter() are not implemented in all browsers, although my specific code was not intended to run in a browser.
You should use the filter method rather than map unless you want to mutate the items in the array, in addition to filtering.
eg.
var filteredItems = items.filter(function(item)
{
return ...some condition...;
});
[Edit: Of course you could always do sourceArray.filter(...).map(...) to both filter and mutate]
Inspired by writing this answer, I ended up later expanding and writing a blog post going over this in careful detail. I recommend checking that out if you want to develop a deeper understanding of how to think about this problem--I try to explain it piece by piece, and also give a JSperf comparison at the end, going over speed considerations.
That said, **The tl;dr is this:
To accomplish what you're asking for (filtering and mapping within one function call), you would use Array.reduce()**.
However, the more readable and (less importantly) usually significantly faster2 approach is to just use filter and map chained together:
[1,2,3].filter(num => num > 2).map(num => num * 2)
What follows is a description of how Array.reduce() works, and how it can be used to accomplish filter and map in one iteration. Again, if this is too condensed, I highly recommend seeing the blog post linked above, which is a much more friendly intro with clear examples and progression.
You give reduce an argument that is a (usually anonymous) function.
That anonymous function takes two parameters--one (like the anonymous functions passed in to map/filter/forEach) is the iteratee to be operated on. There is another argument for the anonymous function passed to reduce, however, that those functions do not accept, and that is the value that will be passed along between function calls, often referred to as the memo.
Note that while Array.filter() takes only one argument (a function), Array.reduce() also takes an important (though optional) second argument: an initial value for 'memo' that will be passed into that anonymous function as its first argument, and subsequently can be mutated and passed along between function calls. (If it is not supplied, then 'memo' in the first anonymous function call will by default be the first iteratee, and the 'iteratee' argument will actually be the second value in the array)
In our case, we'll pass in an empty array to start, and then choose whether to inject our iteratee into our array or not based on our function--this is the filtering process.
Finally, we'll return our 'array in progress' on each anonymous function call, and reduce will take that return value and pass it as an argument (called memo) to its next function call.
This allows filter and map to happen in one iteration, cutting down our number of required iterations in half--just doing twice as much work each iteration, though, so nothing is really saved other than function calls, which are not so expensive in javascript.
For a more complete explanation, refer to MDN docs (or to my post referenced at the beginning of this answer).
Basic example of a Reduce call:
let array = [1,2,3];
const initialMemo = [];
array = array.reduce((memo, iteratee) => {
// if condition is our filter
if (iteratee > 1) {
// what happens inside the filter is the map
memo.push(iteratee * 2);
}
// this return value will be passed in as the 'memo' argument
// to the next call of this function, and this function will have
// every element passed into it at some point.
return memo;
}, initialMemo)
console.log(array) // [4,6], equivalent to [(2 * 2), (3 * 2)]
more succinct version:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
Notice that the first iteratee was not greater than one, and so was filtered. Also note the initialMemo, named just to make its existence clear and draw attention to it. Once again, it is passed in as 'memo' to the first anonymous function call, and then the returned value of the anonymous function is passed in as the 'memo' argument to the next function.
Another example of the classic use case for memo would be returning the smallest or largest number in an array. Example:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val)
// ^this would return the largest number in the list.
An example of how to write your own reduce function (this often helps understanding functions like these, I find):
test_arr = [];
// we accept an anonymous function, and an optional 'initial memo' value.
test_arr.my_reducer = function(reduceFunc, initialMemo) {
// if we did not pass in a second argument, then our first memo value
// will be whatever is in index zero. (Otherwise, it will
// be that second argument.)
const initialMemoIsIndexZero = arguments.length < 2;
// here we use that logic to set the memo value accordingly.
let memo = initialMemoIsIndexZero ? this[0] : initialMemo;
// here we use that same boolean to decide whether the first
// value we pass in as iteratee is either the first or second
// element
const initialIteratee = initialMemoIsIndexZero ? 1 : 0;
for (var i = initialIteratee; i < this.length; i++) {
// memo is either the argument passed in above, or the
// first item in the list. initialIteratee is either the
// first item in the list, or the second item in the list.
memo = reduceFunc(memo, this[i]);
// or, more technically complete, give access to base array
// and index to the reducer as well:
// memo = reduceFunc(memo, this[i], i, this);
}
// after we've compressed the array into a single value,
// we return it.
return memo;
}
The real implementation allows access to things like the index, for example, but I hope this helps you get an uncomplicated feel for the gist of it.
That's not what map does. You really want Array.filter. Or if you really want to remove the elements from the original list, you're going to need to do it imperatively with a for loop.
Array Filter method
var arr = [1, 2, 3]
// ES5 syntax
arr = arr.filter(function(item){ return item != 3 })
// ES2015 syntax
arr = arr.filter(item => item != 3)
console.log( arr )
You must note however that the Array.filter is not supported in all browser so, you must to prototyped:
//This prototype is provided by the Mozilla foundation and
//is distributed under the MIT license.
//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
if (!Array.prototype.filter)
{
Array.prototype.filter = function(fun /*, thisp*/)
{
var len = this.length;
if (typeof fun != "function")
throw new TypeError();
var res = new Array();
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in this)
{
var val = this[i]; // in case fun mutates this
if (fun.call(thisp, val, i, this))
res.push(val);
}
}
return res;
};
}
And doing so, you can prototype any method you may need.
TLDR: Use map (returning undefined when needed) and then filter.
First, I believe that a map + filter function is useful since you don't want to repeat a computation in both. Swift originally called this function flatMap but then renamed it to compactMap.
For example, if we don't have a compactMap function, we might end up with computation defined twice:
let array = [1, 2, 3, 4, 5, 6, 7, 8];
let mapped = array
.filter(x => {
let computation = x / 2 + 1;
let isIncluded = computation % 2 === 0;
return isIncluded;
})
.map(x => {
let computation = x / 2 + 1;
return `${x} is included because ${computation} is even`
})
// Output: [2 is included because 2 is even, 6 is included because 4 is even]
Thus compactMap would be useful to reduce duplicate code.
A really simple way to do something similar to compactMap is to:
Map on real values or undefined.
Filter out all the undefined values.
This of course relies on you never needing to return undefined values as part of your original map function.
Example:
let array = [1, 2, 3, 4, 5, 6, 7, 8];
let mapped = array
.map(x => {
let computation = x / 2 + 1;
let isIncluded = computation % 2 === 0;
if (isIncluded) {
return `${x} is included because ${computation} is even`
} else {
return undefined
}
})
.filter(x => typeof x !== "undefined")
I just wrote array intersection that correctly handles also duplicates
https://gist.github.com/gkucmierz/8ee04544fa842411f7553ef66ac2fcf0
// array intersection that correctly handles also duplicates
const intersection = (a1, a2) => {
const cnt = new Map();
a2.map(el => cnt[el] = el in cnt ? cnt[el] + 1 : 1);
return a1.filter(el => el in cnt && 0 < cnt[el]--);
};
const l = console.log;
l(intersection('1234'.split``, '3456'.split``)); // [ '3', '4' ]
l(intersection('12344'.split``, '3456'.split``)); // [ '3', '4' ]
l(intersection('1234'.split``, '33456'.split``)); // [ '3', '4' ]
l(intersection('12334'.split``, '33456'.split``)); // [ '3', '3', '4' ]
First you can use map and with chaining you can use filter
state.map(item => {
if(item.id === action.item.id){
return {
id : action.item.id,
name : item.name,
price: item.price,
quantity : item.quantity-1
}
}else{
return item;
}
}).filter(item => {
if(item.quantity <= 0){
return false;
}else{
return true;
}
});
following statement cleans object using map function.
var arraytoclean = [{v:65, toberemoved:"gronf"}, {v:12, toberemoved:null}, {v:4}];
arraytoclean.map((x,i)=>x.toberemoved=undefined);
console.dir(arraytoclean);