JavaScript flatten nested array - javascript

I am trying to flatten any length of a nested array into a single array. Why it's showing array rather than array value?
function flatten(arr) {
var res = [];
for (var i = 0; i < arr.length; i++) {
if (toString.call(arr[i]) === "[object Array]") {
res.push(flatten(arr[i]));
} else {
res.push(arr[i]);
}
}
return res;
}
console.log(flatten([1, 2, [3, [4, 5, [6]]], 7, 8]));
// [1, 2, Array(2), 7, 8]

You are pushing to res the result of flatten, which is an array. Instead Array#concat the result of the inner flatten call to res, and assign the result to res.
Note: to identify an array, you can use Array#isArray.
function flatten(arr) {
var res = [];
for (var i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
res = res.concat(flatten(arr[i]));
} else {
res.push(arr[i]);
}
}
return res;
}
console.log(flatten([1, 2, [3, [4, 5, [6]]], 7, 8])); // [1, 2, Array(2), 7, 8]

You can use concat instead of push and reduce instead of for loop.
const flatten = data => data.reduce((r, e) => {
return r = r.concat(Array.isArray(e) ? flatten(e) : e), r
}, [])
console.log(flatten([1, 2, [3, [4, 5, [6]]], 7, 8]))

You can use the flat() method on the array as follows.
function flatten(arr) {
return arr.flat(10) //the number in brackets are the depth level
}
console.log(flatten([1, 2, [3, [4, 5, [6]]], 7, 8]));

Related

How to triplicate specific items in an array for javascript?

Is there any way to only triplicate certain elements in an array? I want to triplicate the "3" in the array only.
For instance:
const deck = [1, 3, 9, 3, 7];
should become [1, 3, 3, 3, 9, 3, 3, 3, 7]
I have tried the method below, deck is the random array:
var i;
for (let i=0;i<deck.length;i++){
if (deck[i]==3){
return deck.flatMap(x=>[x,x,x]);
}else return deck[i];
}
}
You could write a function that uses flatMap() to map over the array and triplicate the specific values.
const deck = [1, 3, 9, 3, 7];
const triplicate = (number, arr) => {
return arr.flatMap(x => x === number ? [x, x, x]: x);
}
console.log(triplicate(3, deck));
Using Array#flatMap:
const triplicate = (arr = [], number) =>
arr.flatMap(n => n === number ? [n, n, n] : n);
console.log( triplicate([1, 3, 9, 3, 7], 3) );

format JSON object into array of objects

I want to convert the below JSON format
let init = {
test1: [1, 2, 3, 4, 5],
test2: [6, 7, 8, 9, 10]
}
into this format using javascript native methods of array or object (supported in all browsers)
[{
test1: 1,
test2: 6
},{
test1: 2,
test2: 7
},{
test1: 3,
test2: 8
},{
test1: 4,
test2: 9
},{
test1: 5,
test2: 10
}]
I have tried with for loop and below is the code,
let keys = Object.keys(init);
let result = [];
for(let i = 0; i < keys.length; i++){
let key = keys[i];
for(let j = 0; j < init[key].length; j++){
if(i === 0){
let obj1 = {};
obj1[key] = init[key][j];
result.push(obj1);
}else{
let obj2 = result[j];
obj2[key] = init[key][j];
}
}
}
You could use Array.prototype.reduce() to do that.
Iterate on test1 array elements and push a new object to the array accumulator with test1 and test2 properties and their respective values.
let init = {
test1: [1, 2, 3, 4, 5],
test2: [6, 7, 8, 9, 10]
};
let keys = Object.keys(init);
let key1 = keys[0];
let key2 = keys[1];
let result = init[key1].reduce((acc, curr, i) => {
acc.push({
[key1]: curr,
[key2]: init[key2][i]
});
return acc;
}, []);
console.log(result);
As of now, reduce() method is supported in most of the modern browsers. For supporting all browsers, it is better to use for loop, but instead of Object.keys() iterate on object properties or use a polyfill.
let init = {
test1: [1, 2, 3, 4, 5],
test2: [6, 7, 8, 9, 10]
};
let keys = [];
for (let key in init) {
if (init.hasOwnProperty(key)) {
keys.push(key);
}
}
let key1 = keys[0];
let key2 = keys[1];
let result = [];
for (let i = 0; i < key1.length; i++) {
result.push({
[key1]: init[key1][i],
[key2]: init[key2][i]
});
}
console.log(result);
You could use a combination of for...in and Array.forEach to achieve this result in a few lines of code. If you wan't support for all browsers you can better use var instead of let though. https://caniuse.com/#search=let
var init = {
test1: [1, 2, 3, 4, 5],
test2: [6, 7, 8, 9, 10]
}
var result = []
for (var key in init) {
init[key].forEach(function (item, index) {
result[index] ? result[index][key] = item : result[index] = { [key]: item }
})
}
console.log(result)
You could maybe simplify this a bit more by initializing your result with empty objects, that would avoid using a ternary statement. That would look like this:
Disclaimer: This won't work in IE11 because of the lack of Array.fill() support
var init = {
test1: [1, 2, 3, 4, 5],
test2: [6, 7, 8, 9, 10]
}
var result = new Array(Object.keys(init)[0].length).fill().map(Object);
for (var key in init) {
init[key].forEach(function(item, index) {
result[index][key] = item
})
}
console.log(result)
If you do this make sure you don't create an array with Objects that are a reference to the same object in memory: Array.prototype.fill() with object passes reference and not new instance

Javascript - Put array items, including their duplicates, into a new array

I couldn't find an answer to this specific question on S.O.
Let's say I have an array of strings, or in this case, numbers:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
I'd like the output to be:
var output = [[1,1,1], [2], [3,3,3,3,3], [4], [5, 5, 5]];
I was hoping to use Lodash but most of that stuff tends to remove duplicates rather chunk them together into their own array. Maybe some kind of .map iterator?
The order of the output doesn't really matter so much. It just needs to chunk the duplicates into separate arrays that I'd like to keep.
You can use reduce to group the array elements into an object. Use Object.values to convert the object into an array.
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
var result = Object.values(x.reduce((c, v) => {
(c[v] = c[v] || []).push(v);
return c;
}, {}));
console.log(result);
Shorter version:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
var result = Object.values(x.reduce((c, v) => ((c[v] = c[v] || []).push(v), c), {}));
console.log(result);
You can do this with Array.reduce in a concise way like this:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5]
let result = x.reduce((r,c) => (r[c] = [...(r[c] || []), c],r), {})
console.log(Object.values(result))
The exact same with lodash would be:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5]
let result = _.values(_.groupBy(x))
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Using _.values to extract the values of the grouping object and _.groupBy to get the actual groupings
Use Array#prototype#reduce to group them:
const x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
let helperObj = {};
const res = x.reduce((acc, curr) => {
// If key is not present then add it
if (!helperObj[curr]) {
helperObj[curr] = curr;
acc.push([curr]);
}
// Else find the index and push it
else {
let index = acc.findIndex(x => x[0] === curr);
if (index !== -1) {
acc[index].push(curr);
}
}
return acc;
}, []);
console.log(res);
Since you're hoping to use Lodash, you might be interested in groupBy. It returns on object, but the _.values will give you the nested array:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
let groups = _.values(_.groupBy(x))
console.log(groups)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Here's an imperative solution:
var x = [1, 1, 1, 2, 3, 3, 5, 3, 3, 5, 4, 5];
x.sort();
var res = [];
for (const [i, n] of x.entries()) {
if (n !== x[i-1]) res.push([n]);
else res[res.length-1].push(n);
}
console.log(res);

Merge elements of array with comma with max counter

So I have an array of ids something like this:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
I need a function that will be called like mergeArray(arr, 3), and it should return comma separated values with maximum of 3 elements like this:
const newArr = ['1,2,3', '4,5,6', '7,8,9', '10,11'];
How can I do this? If possible with ES6 functions for simpler code.
slice your array into 3 lengths arrays and directly join them
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
const mergeArray = (arr, size) => {
let res = [];
for (i = 0; i < arr.length; i += size) {
res.push(arr.slice(i, i + size).join(','));
}
return res;
}
console.log(mergeArray(arr, 3));
You can split() the array into the specific size and join() them before pushing into the resulting array:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
var i, j, newArr=[], size = 3;
for (i=0,j=arr.length; i<j; i+=size) {
newArr.push(arr.slice(i, i+size).join());
}
console.log(newArr);
One of the ways to do it is with Array.prototype.reduce and Array.prototype.map:
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
function mergeArray(arr, n) {
return arr
.reduce((all, el, i) => {
const ind = Math.floor(i/n);
all[ind] = [...all[ind] || [], el]
return all;
},[])
.map(a => a.join(','))
}
console.log(mergeArray(arr, 3));
You could join the array and match the wanted parts with a regular expression.
var data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
result = data.join(',').match(/\d+(,\d+(,\d+)?)?/g)
console.log(result);

Finding Symmetric Difference in an array test fail

sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]) should return [1, 4, 5]
The expected return is shown above. But I couldn't find why it fails this test. What kind of fix is needed to code below?
function sym(args) {
//debugger;
var arr=Array.from(arguments);
var resArr=[];
arr.forEach(function(arrVal){
var c=0;
arrVal.forEach(function(val,index){
console.log("arrVal",arrVal,"index",index,"val",val,"|",arrVal.slice(index+1-c));
if(index<arrVal.length-1 && arrVal.slice(index+1-c).indexOf(val)!==-1){
console.log("here");
arrVal.splice(index-c,1);
c++;
}
console.log("arrVal",arrVal,"index",index,"|",arrVal);
});
resArr.push(arrVal);
});
console.log(resArr);
resArr=resArr.reduce(function(acc,curr){
return acc.concat(curr.filter(function(val){
var notContains=acc.indexOf(val)==-1;
if(!notContains)
acc.splice(acc.indexOf(val),1);
return notContains;
}));
},[]);
console.log(resArr);
return resArr;
}
sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]);
You could use a more concise version with filtering duplicates.
function sym(array) {
return array.reduce(function (r, a) {
return r.concat(a.filter(function (a, i, aa) {
return i === aa.indexOf(a);
})).filter(function (a, i, aa) {
return aa.indexOf(a) === aa.lastIndexOf(a);
});
}, []);
}
console.log(sym([[1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]])); // [1, 4, 5]
Use Sets. Their support should be sufficent. Extend their prototype and benefit from meaningful methods (union, intersection and difference taken from MDN):
Set.prototype.union = function(setB) {
var union = new Set(this);
for (var elem of setB) {
union.add(elem);
}
return union;
}
Set.prototype.intersection = function(setB) {
var intersection = new Set();
for (var elem of setB) {
if (this.has(elem)) {
intersection.add(elem);
}
}
return intersection;
}
Set.prototype.difference = function(setB) {
var difference = new Set(this);
for (var elem of setB) {
difference.delete(elem);
}
return difference;
}
Set.prototype.symmetricDifference = function(setB) {
return this.union(setB).difference(this.intersection(setB));
}
var set1 = new Set([1, 1, 2, 5]);
var set2 = new Set([2, 2, 3, 5]);
var set3 = new Set([3, 4, 5, 5]);
var result = set1.symmetricDifference(set2).symmetricDifference(set3);
console.log(result); // as Set
console.log([...result]); // as Array

Categories