This question already has answers here:
Javascript recursive array flattening
(27 answers)
Merge/flatten an array of arrays
(84 answers)
Closed 5 years ago.
I want to write a function that can deep flatten a given array. For example:
deepFlatten([]); // []
deepFlatten([1, 2, 3]); // [1, 2, 3]
deepFlatten([[1, 2, 3], ["a", "b", "c"], [1, 2, 3]]); // [1, 2, 3, "a", "b", "c", 1, 2, 3]
deepFlatten([[3], [4], [5]], [9], [9], [8], [[1, 2, 3]]]); // [3, 4, 5, 9, 9, 8, 1, 2, 3]
I try to solve this recursively and so far I've got this:
var deepFlatten = function (array){
var result = [];
array.forEach(function (elem) {
if (Array.isArray(elem)) {
result.concat(deepFlatten(elem)); // problem probably lies here
} else {
result.push(elem);
}
});
return result;
};
This however only pushes non-array elements to result and completely ignores the concatenating part. How can I fix this or is there a better way to write this function without the help of any external library?
You just need to set result to result = result.concat(deepFlatten(elem))
var deepFlatten = function (array){
var result = [];
array.forEach(function (elem) {
if (Array.isArray(elem)) {
result = result.concat(deepFlatten(elem)); // Fix here
} else {
result.push(elem);
}
});
return result;
};
console.log(deepFlatten([]))
console.log(deepFlatten([1, 2, 3]))
console.log(deepFlatten([[1, 2, 3], ["a", "b", "c"], [1, 2, 3]]))
console.log(deepFlatten([[[3], [4], [5]], [9], [9], [8], [[1, 2, 3]]]))
Instead you can use reduce() and spread syntax instead of concat.
var deepFlatten = function (array){
return array.reduce(function(r, e) {
return Array.isArray(e) ? r.push(...deepFlatten(e)) : r.push(e), r
}, [])
};
console.log(deepFlatten([]))
console.log(deepFlatten([1, 2, 3]))
console.log(deepFlatten([[1, 2, 3], ["a", "b", "c"], [1, 2, 3]]))
console.log(deepFlatten([[[3], [4], [5]], [9], [9], [8], [[1, 2, 3]]]))
Your code is mostly fine. .concat returns a new array, it doesn't modify the original. If you change
result.concat(deepFlatten(elem)); // problem probably lies here
to:
result = result.concat(deepFlatten(elem)); // problem probably lies here
i think it gives the correct results.
Related
This question already has answers here:
How to calculate intersection of multiple arrays in JavaScript? And what does [equals: function] mean?
(18 answers)
Closed 1 year ago.
There is an array containing multiple sub-arrays, each with some elements.
For example:
const myArray = [[1,2,3],[2,3,4,5,6,7],[2,3,4],[2,3,6,11]];
in this case it should return [2,3] as these are the common elements in all sub-arrays.
Is there an efficient way to do that?
I wrote a function that does it for 2 sub-arrays, I don't think it's efficient to call it for every sub-array:
const filteredArray = array1.filter(value => array2.includes(value));
You could do like this:
const myArray = [[1, 2, 3], [2, 3, 4, 5, 6, 7], [2, 3, 4], [2, 3, 6, 11]];
const distinctValues = [...new Set(myArray.flat(1))];
const intersection = distinctValues.filter(x => myArray.every(y => y.includes(x)));
console.log(intersection);
You could reduce the array with filtering the nested arrays with a Set.
const
data = [[1, 2, 3], [2, 3, 4, 5, 6, 7], [2, 3, 4], [2, 3, 6, 11]],
common = data.reduce((a, b) => b.filter(Set.prototype.has, new Set(a)));
console.log(common);
Given multidimensional array (of any size and depth):
const multidimensionalArray = [1, [2, [3, [4, [5]]]], [6], [7, [8], [9]]];
I need to convert it into 2 dimensions array following example below (the idea is that each nested value should be converted into an array of all parents + this value).
Expected 2 dimensions array :
const twoDimensionsArray = [
[1],
[1, 2],
[1, 2, 3],
[1, 2, 3, 4],
[1, 2, 3, 4, 5],
[1, 6],
[1, 7],
[1, 7, 8],
[1, 7, 9],
];
Could you please help me to solve the problem?
A recursive call for each nested array ought to do the trick.
NOTE: The following may not be complete for your use case - your data needs to be in a specific order for this to work - but I think this should be clean enough as an example:
const customFlatten = (arr, parents = [], output = []) => {
for (const item of arr) {
// If not an array...
if (!Array.isArray(item)) {
parents.push(item) // update parents for recursive calls
output.push(parents.slice(0)) // add entry to output (copy of _parents)
// If an array...
} else {
customFlatten(item, parents.slice(0), output) // recursive call
}
}
return output
}
console.log(customFlatten([1, [2, [3, [4, [5]]]], [6], [7, [8], [9]]]))
I'm trying to solve this problem. Essentially, I have a array of keys, and an array of values within objects, and I want those values to have keys.
Below is my best attempt so far - usually use python so this is a bit confusing for me.
var numbers = [3, 4, 5,6]
var selection = [[1, 2, 3, 4], [6, 5, 4, 3], [2, 9, 4]]
var result = [];
for (arr in selection) {
numbers.forEach(function (k, i) {
result[k] = arr[i]
})
};
console.log(result);
The output I'm looking for is like this,
results = [{3:1,4:2,5:3,6:4}, {..},..]
Love some pointers to getting the right output.
Note. This is for google appscript! So can't use certain javascript functions (MAP I think doesn't work, unsure of reduce).
Cheers!
Use map on selection and Object.assign
var numbers = [3, 4, 5, 6];
var selection = [
[1, 2, 3, 4],
[6, 5, 4, 3],
[2, 9, 4]
];
var result = selection.map(arr =>
Object.assign({}, ...arr.map((x, i) => ({ [numbers[i]]: x })))
);
console.log(result);
Create a separate function which take keys and values as arguments and convert it into object using reduce(). Then apply map() on selections and make an object for each subarray using that function
var numbers = [3, 4, 5,6]
var selection = [[1, 2, 3, 4], [6, 5, 4, 3], [2, 9, 4]]
function makeObject(keys, values){
return keys.reduce((obj, key, i) => ({...obj, [key]: values[i]}),{});
}
const res = selection.map(x => makeObject(numbers, x));
console.log(res)
Create a new object from scratch for each number array:
const selection = [
[1, 2, 3, 4],
[6, 5, 4, 3],
[2, 9, 4],
];
function objMaker(numarr) {
const numbers = [3, 4, 5, 6];
numarr.forEach((num, i) => (this[numbers[i]] = num));
}
console.info(selection.map(numarr => new objMaker(numarr)));
I have the following code:
function uniteUnique(arr) {
//Create a single Array of value
arr = arguments[0].concat(arguments[1], arguments[2]);
//Reduce the Array to unique values only
arr = arr.reduce((pre, curr) => {
//Some function to reduce values
});
return arr;
}
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
The goal is to produce a single Array containing only unique values while maintaining the order.
Currently it returns:
[1, 3, 2, 5, 2, 1, 4, 2, 1]
I'm wanting to reduce this to:
[1, 3, 2, 5, 4]
You can use Set for that:
function uniteUnique(...args) {
return [...new Set([].concat(...args))];
}
var u = uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
console.log(u);
It maintains insertion order, and by nature only contains unique values.
In ES5 you could do it by maintaining the used values as properties of a temporary object, while building the result array:
function uniteUnique(/* args */) {
return [].concat.apply([], arguments).reduce(function (acc, v) {
if (!acc[0][v]) acc[0][v] = acc[1].push(v); // assigns new length, i.e. > 0
return acc;
}, [ Object.create(null), [] ])[1];
}
var u = uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
console.log(u);
You can use the Set object since it already keeps your values unique in one object:
const mySet = new Set([1, 3, 2, 5, 2, 1, 4, 2, 1]);
// returns: Set { 1, 3, 4, 5 };
const arrayUniques = [...mySet];
console.log(arrayUniques);
// returns: [1, 3, 4, 5];
How to simply flatten array in jQuery? I have:
[1, 2, [3, 4], [5, 6], 7]
And I want:
[1, 2, 3, 4, 5, 6, 7]
You can use jQuery.map, which is the way to go if you have the jQuery Library already loaded.
$.map( [1, 2, [3, 4], [5, 6], 7], function(n){
return n;
});
Returns
[1, 2, 3, 4, 5, 6, 7]
Use the power of JavaScript:
var a = [[1, 2], 3, [4, 5]];
console.log( Array.prototype.concat.apply([], a) );
//will output [1, 2, 3, 4, 5]
Here's how you could use jquery to flatten deeply nested arrays:
$.map([1, 2, [3, 4], [5, [6, [7, 8]]]], function recurs(n) {
return ($.isArray(n) ? $.map(n, recurs): n);
});
Returns:
[1, 2, 3, 4, 5, 6, 7, 8]
Takes advantage of jQuery.map as well as jQuery.isArray.
var a = [1, 2, [3, 4], [5, [6, [7, 8]]]];
var b = [];
function flatten(e,b){
if(typeof e.length != "undefined")
{
for (var i=0;i<e.length;i++)
{
flatten(e[i],b);
}
}
else
{
b.push(e);
}
}
flatten(a,b);
console.log(b);
The flatten function should do it, and this doesn't require jQuery. Just copy all of this into Firebug and run it.
To recursively flatten an array you can use the native Array.reduce function. The is no need to use jQuery for that.
function flatten(arr) {
return arr.reduce(function flatten(res, a) {
Array.isArray(a) ? a.reduce(flatten, res) : res.push(a);
return res;
}, []);
}
Executing
flatten([1, 2, [3, 4, [5, 6]]])
returns
[ 1, 2, 3, 4, 5, 6 ]
You can use jQuery.map():
callback( value, indexOrKey )The function to process each item
against. The first argument to the function is the value; the second
argument is the index or key of the array or object property. The
function can return any value to add to the array. A returned array
will be flattened into the resulting array. Within the function, this
refers to the global (window) object.
Use recursion if you have multiple levels:
flaten = function(flatened, arr) {
for(var i=0;i<arr.length;i++) {
if (typeof arr[i]!="object") {
flatened.push(arr[i]);
}
else {
flaten(flatened,arr[i]);
}
}
return;
}
a=[1,[4,2],[2,7,[6,4]],3];
b=[];
flaten(b,a);
console.log(b);
You can use Array.prototype.reduce which is technically not jQuery, but valid ES5:
var multidimensionArray = [1, 2, [3, 4], [5, 6], 7];
var initialValue = [];
var flattened = multidimensionArray.reduce(function(accumulator, current) {
return accumulator.concat(current);
}, initialValue);
console.log(flattened);
Old question, I know, but...
I found this works, and is fast:
function flatten (arr) {
b = Array.prototype.concat.apply([], arr);
if (b.length != arr.length) {
b = flatten(b);
};
return b;
}
You need arr.flat([depth])
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]