Recursively make one level array from multi levels array in JavaScript - javascript

I'm confused a little, please help me anyone.
This is what I have
var arr = [
1,
2,
[11, 12, 13],
3,
[11, 12,
[21, 22]
]
];
As you can see, it's multi-lever array. Using recursion I need to make a one level array from it, which contains all elements from its children. Should be like this:
[1,2,11,12,13,3,11,12,21,22]
Here's how I'm doing it:
function getAllNumbers(arr) {
var allNumbers = [];
arr.forEach(function (el) {
if (Array.isArray(el)) {
allNumbers.concat(getAllNumbers(el))
} else {
allNumbers.push(el)
}
});
return allNumbers;
}
and it's not working. Gives me back only first level, like this: [1,2,3]
I'm particularly interested in recursion so please don't try to find other way.
please help
P.S. I can easily find sum of all elements with similar method just a little modified, but cannot do this :(

Almost everything was fine :)
just
The concat() method returns a new array comprised of the array on which it is called joined with the array(s) and/or value(s) provided as arguments.
so, instead of
allNumbers.concat(getAllNumbers(el))
should be
allNumbers = allNumbers.concat(getAllNumbers(el))
and it works :)

Related

lodash _.partition method explained

I just discovered lodash.js and it's freaking GREAT man, however I stumbled onto an example which had me scratching my head.
let numbers = [4, 8, 15, 16, 23, 42];
let isEven = function(n) {
return n % 2 === 0;
};
let [evens, odds] = _.partition(numbers, isEven);
// evens: [4, 8, 16, 42]
// odds: [15, 23]
According to the documentation partition creates ONE array which contains two arrays containing results which returned true or false respectively, then how the outcome of the function TWO arrays?
Because the destructuring assignment allows you to assign the first element of the returned array to variable evens, and the second to odds. Since the returned array contains two arrays, both of the variables now refer to one-dimensional arrays.

Stand in Line Freecodecamp

Im currently working thru the exercises on the javascript portion of the freecodecamp site and Im trying to understand why a particular method worked in solving it.
function nextInLine(arr, item) {
// Your code here
arr.push(item);
var firstItem = arr.shift(arr);
return firstItem; // Change this line
}
Im trying to understand why I had to create the variable firstItem in the first place? Is there another way I could of went about solving this exercise? If so please let me know how you went about solving it.
Welcome to Stack Overflow :)
I've also gone through this task as part of undertaking the Free Code Camp front end certification. For reference, this is the task: https://www.freecodecamp.com/challenges/stand-in-line
Write a function nextInLine which takes an array (arr) and a number
(item) as arguments. Add the number to the end of the array, then
remove the first element of array. The nextInLine function should then
return the element that was removed.
While your solution delivers the desired outcome, it is possible to solve this task without declaring a variable (firstItem in your code). I've prepared and demo with description for you here: http://codepen.io/PiotrBerebecki/pen/xEYbgv
The crucial thing is to understand that:
The shift() method removes the first element from an array AND returns
that element. This method changes the length of the array.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/shift
function nextInLine(arr, item) {
// arr is now: [5,6,7,8,9]
arr.push(item); // add 10 to the and of array
// arr is now: [5,6,7,8,9,10]
return arr.shift(); // remove first element of arr (5)
// and then return this first element (5),
// arr is now [6,7,8,9,10]
}
var testArr = [5,6,7,8,9];
console.log(nextInLine(testArr, 10)); // 5
console.log("After: " + JSON.stringify(testArr)); // After: [6,7,8,9,10]
The .shift function doesn't use any arguments. It just removes the first element of array one by one.
Here is the correct code.
function nextInLine(arr, item) {
arr.push(item);
var remove=arr.shift();
}
return arr.shift(arr);
with out declaring the variable to return
function nextInLine(arr, item){
arr.push(item); //this will add new element to the array, for our case, our array become [10, 11, 12, 13, 14, 15]
return arr.shift(arr); //the shift() method will remove the first //element and then return its value.
//for our case, our new array becomes [11, 12, 13, 14 ,15], 10 will be returned as the value of the removed element
return item; //will return the value of the item argument
};
const myArray = [10, 11, 12, 13, 14];
console.log(nextInLine(myArray, 15));
//array.push(item) in this case will add 15 to the end of the array, and the new array will now be [10, 11, 12, 13, 14, 15]
console.log(myArray);
//arr.shift(arr) will take the new array[10, 11, 12, 13, 14, 15] and remove the first element, which is "10", and then return it. Our new array will now be [11, 12, 13, 14, 15].

Why would this example iterate through an array to sort, instead of using the .sort() method?

I'm going through some basic array challenges on w3.
Here is the task given:
Write a JavaScript program to sort the items of an array.
Sample array : var arr1 = [ 3, 8, 7, 6, 5, -4, 3, 2, 1 ];
Sample Output : -4,-3,1,2,3,5,6,7,8
Here is their given solution:
var arr1=[-3,8,7,6,5,-4,3,2,1];
var arr2=[];
var min=arr1[0];
var pos;
max=arr1[0];
for (i=0; i<arr1.length; i++)
{
if (max<arr1[i]) max=arr1[i];
}
for (var i=0;i<arr1.length;i++)
{
for (var j=0;j<arr1.length;j++)
{
if (arr1[j]!="x")
{
if (min>arr1[j])
{
min=arr1[j];
pos=j;
}
}
}
arr2[i]=min;
arr1[pos]="x";
min=max;
}
alert(arr2);
This is what I came up with... :
var arr1 = [ -3, 8, 7, 6, 5, -4, 3, 2, 1 ];
arr1.sort(function(a, b){return a-b});
console.log(arr1);
Why does it seem to me that their solution is so much more "convoluted"? Is it necessary to add their solution to protect against a specific use case?
To sort an array, always use built-in functions rather that writing your own. It takes away the pain of useless debugging and, actually, re-inventing the wheel.
.sort() is absolutely OK.
Moreover, not only the long solution is "convoulted", it's O(n^2) whist the native sort is usually faster.
And it's doing some weird stuff with the 'x' value and uses == instead of ===, so it looks not so good at all.

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;
});

What function acts as .SelectMany() in jQuery?

Let me explain more:
we know that map function in jQuery acts as .Select() (as in LINQ).
$("tr").map(function() { return $(this).children().first(); }); // returns 20 tds
now the question is how can we have .SelectMany() in jQuery?
$("tr").map(function() { return $(this).children(); }); // returns 10 arrays not 20 tds!
here is my example in action: http://jsfiddle.net/8aLFQ/4/
"l2" should be 8 if we have selectMany.
[NOTE] please don't stick to this example, above code is to just show what I mean by SelectMany() otherwise it's very easy to say $("tr").children();
Hope it's clear enough.
map will flatten native arrays. Therefore, you can write:
$("tr").map(function() { return $(this).children().get(); })
You need to call .get() to return a native array rather than a jQuery object.
This will work on regular objects as well.
var nested = [ [1], [2], [3] ];
var flattened = $(nested).map(function() { return this; });
flattened will equal [1, 2, 3].
You want this:
$("tr").map(function() { return $(this).children().get(); });
Live demo: http://jsfiddle.net/8aLFQ/12/
You're going to kick yourself:
$("tr").map(function() { return [ $(this).children() ]; });
It's the simple things in life you treasure.
-- Fred Kwan
EDIT:
Wow, that will teach me to not to test answers thoroughly.
The manual says that map flattens arrays, so I assumed that it would flatten an array-like object. Nope, you have to explicit convert it, like so:
$("tr").map(function() { return $.makeArray($(this).children()); });
Things should be as simple as possible, but no simpler. -- Albert Einstein
$.map expects a value (or an array of values) returned. The jQuery object you are returning is being used as a "value" instead of an "array" (which get flattened)
All you need to do is return the array of DOM elements. jQuery provides a .get() method that returns a plain array from a selection.
$("tr").map(function() { return $(this).children().get() });
Of course, I understand this is a very contrived example, since $("tr").children() does the same thing with a lot less function calls.
http://jsfiddle.net/gnarf/8aLFQ/13/
I had the same question for regular arrays, and this is the only reference I could find in StackOverflow, so I'll add the answer I came up with.
For regular arrays, you can use
Array.prototype.selectMany = function (selector) {
return this.map(selector).reduce(function (a, b) {
return a.concat(b);
});
};
Thus [[1, 2], [3, 4], [5, 6, 7]].selectMany(function (a) { return a; }) evaluates to [1, 2, 3, 4, 5, 6, 7].
To use this in jQuery, you have to convert your jQuery set into an array before using it:
var result = $("tr").get().selectMany(function(a) {
return Array.prototype.slice.call(a.childNodes);
});
Not sure about .selectMany() but you could change the position of .children to get the desired result.
var l2 = $("tr").children().map(function() { return $(this); }).length;
http://jsfiddle.net/8aLFQ/5/
EDIT
I think I better understand what you're after following the comments.
You can call $.makeArray(l2) to return what you are after... that is 8 objects/arrays
http://jsfiddle.net/8aLFQ/10/

Categories