I can not figure out why my code does not flatten out the nested arrays as indicated. I'd greatly appreciate some help here. I used a recursion to get to the actual value of the nested array. I tried to debug my code, and it seems to replace my results array every time the recursion takes place.
//Helper methods
function toType(obj){
return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}
function each(collection, callback){
if (Array.isArray(collection)){
for (var i = 0; i < collection.length; i++){
callback(collection[i], i, collection)
}
} else {
for (var i in collection){
callback(collection[i], i, collection)
}
}
}
//Flatten function
function flatten(array, isShallow=false, callback){
var results = [];
each(array, function(item){
if (!!isShallow && toType(item) === 'array'){
each (item, function(value){
results.push(value);
})
} else if (toType(item) !== 'array'){
results.push(item);
} else {
return flatten(item)
}
})
return results;
}
flatten([1, [2], [3, [[4]]]]);
// ---> [1]
-
Golf answer: function flatten(a){return a.reduce(function(a,b){return a.concat(b.map?flatten(b):b)},[])}000– 0002014年06月17日 21:20:30 +00:00Commented Jun 17, 2014 at 21:20
-
1In what environment you are running this code? It’s required to ECMA6 support as you are using developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Krzysztof Safjanowski– Krzysztof Safjanowski2014年06月17日 21:23:18 +00:00Commented Jun 17, 2014 at 21:23
5 Answers 5
Your problem appears to be with this line:
return flatten(item)
Returning here is a problem because the loop will end and the current entries in results will be ignored, as well as the remaining items. The line should be changed to instead append the results of
flatten(item)
to results array via push.
I recommend using a library for this sort of thing. http://underscorejs.org/#flatten is a great one!
4 Comments
Please see the refactored code below.
The major change is that instead of creating new copies of results, we are passing it to subsequent calls to flatten as a reference.
Please see the added comments
//Helper methods
function toType(obj){
return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
}
function each(collection, callback){
if (Array.isArray(collection)){
for (var i = 0; i < collection.length; i++){
callback(collection[i], i, collection)
}
} else if(typeof collection === 'object'){
//type number was failing here
for (var i in collection){
callback(collection[i], i, collection)
}
}
else {
//default for primitive types
callback(collection, 0, collection);
}
}
//Flatten function
//Removed isShallow, how do we know if its shallow or not?
//Added results as arg, so we only manipulate the reference to results
//And to not create multiple scopes of var results;
function flatten(array, results, callback){
results = results || [];
each(array, function(item){
//removed 3rd if clause not needed.
//Only need to know if item is an object or array
if (toType(item) === 'array' || toType(item) === 'object'){
each (item, function(value){
flatten(value,results);
})
} else {
results.push(item);
}
})
return results;
}
var array1 = [1,[2,[3,4]]];
var array2 = [5,[6,[7,[8, {a:9,b:[10,11,12]}]]]];
var obj = {a:array1, b:array2};
console.log(flatten(array1)); // [ 1, 2, 3, 4 ]
console.log(flatten(array2)); // [ 5, 6, 7, 8, 9, 10, 11, 12 ]
console.log(flatten(obj)); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ]
3 Comments
flatten()?You can do something like that:
function flatten(array, i) {
i = i || 0;
if(i >= array.length)
return array;
if(Array.isArray(array[i])) {
return flatten(array.slice(0,i)
.concat(array[i], array.slice(i+1)), i);
}
return flatten(array, i+1);
}
Example:
var weirdArray = [[],1,2,3,[4,5,6,[7,8,9,[10,11,[12,[[[[[13],[[[[14]]]]]]]]]]]]]
flatten(weirdArray);
//returns ==> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
Comments
The best way to flatten you array in javascript is to use splice function of Array. Please follow the following code. It works for nesting as well.
function flattenArray(arr){
for(var i=0;i<arr.length;i++){
if(arr[i] instanceof Array){
Array.prototype.splice.apply(arr,[i,1].concat(arr[i]))
}
}
return arr;
}
Comments
Use underscore.js's flatten function (http://underscorejs.org/#flatten). Underscore.js is a 3rd party library with 80 some-odd functions to make your life as a javascript programmer easier. Don't reinvent the wheel.
var _ = require('underscore');
_.flatten([1, [2], [3, [[4]]]]);
=> [1, 2, 3, 4];