Concatenate an unknown number of arrays in Javascript/NodeJS - javascript

I have a function in one of my controllers where I populate an array of references to a document, which, when populated, have embedded arrays themselves.
Here's an example:
The mongoose populate function gives me an array of objects. Within each of those objects is an array:
[{ name: Test, array: [ 1, 2, 3, 4, 5 ] }, { name: TestAgain, array: [1, 2, 3, 4, 5] }, { name: Test^3, array: [1, 2, 3, 4, 5]}, {...
The desired output would be:
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, ...]
I need to concatenate all of the "arrays" within the populated references. How can I do this without knowing how many arrays there are?
For reference, here is (generally) what my function looks like:
exports.myFunctionName = function ( req, res, next )
Document.findOne({ 'document_id' : decodeURIComponent( document_id )}).populate('array_containing_references').exec(function( err, document)
{
//Here I need to concatenate all of the embedded arrays, then sort and return the result as JSON (not worried about the sorting).
});

Assuming your input is in the document variable, try this:
var output = document.reduce(function (res, cur) {
Array.prototype.push.apply(res, cur.array);
return res;
}, []);
Or this:
var output = [];
document.forEach(function(cur) {
Array.prototype.push.apply(output, cur.array);
});

You want to take each document and do something with a property from it. Sounds like a great use case for Array.prototype.map!
map will get each document's array value and return you an array of those values. But, you don't want a nested array so we simply use Array.prototype.concat to flatten it. You could also use something like lodash/underscore.js flatten method.
var a = [
{ name: 'test1', array: [1, 2, 3, 4, 5]},
{ name: 'test2', array: [1, 2, 3, 4, 5]},
{ name: 'test3', array: [1, 2, 3, 4, 5]}
];
var results = Array.prototype.concat.apply([], a.map(function(doc) { return doc.array; }));
document.body.innerHTML = results;

Related

JS Javascript - How to put array values in another array by indexes?

I have this array/object:
const template = {0: [0, 1, 2, 3, 4, 5], 1: [0, 1, 2, 3, 4, 6]}
// I have the above but happy to convert the below if it helps:
//const templateArr = [[0, 1, 2, 3, 4, 5],[0, 1, 2, 3, 4, 6]]
Then I have an array that I want to map into that sequence:
const myArray = ["Q","W","A","S","Z","X,"E","R","D"] // for example
My intention it to have following result:
let myResult = [["Q", "W", "A", "S", "Z", "X"],["Q", "W", "A", "S", "Z", "E"]]
So all the values of myArray are in the positions set by template.
I'm not sure if I should use .map() or something else... Can someone point me in the right direction??
Thank you so much!
Yes, .map() is the right tool here. You can use two, one outer one to map over your inner arrays from templateArr, and then an inner map to map over the numbers (indexes) in your inner arrays, which will transform (ie: map) each number to the corresponding value at the index from myArray:
const templateArr = [[0, 1, 2, 3, 4, 5],[0, 1, 2, 3, 4, 6]];
const myArray = ["Q","W","A","S","Z","X","E","R","D"];
const res = templateArr.map(inner => inner.map(idx => myArray[idx]));
console.log(JSON.stringify(res)); // JSON.stringify to pretty-print
Object.values will convert your template into array of arrays, then simply do map over it and another inner map over indicies and replace
them with particular letter from myArray.
Code:
const template = {0: [0, 1, 2, 3, 4, 5], 1: [0, 1, 2, 3, 4, 6]}
const myArray = ["Q","W","A","S","Z","X","E","R","D"]
const res = Object.values(template)
.map(a => a.map(idx => myArray[idx] ?? null))
console.log(res)
.as-console-wrapper { max-height: 100% !important; top: 0; } /* ignore this */
I think this should work:
const res = templateArr.map( (arr) => {
return arr.map( (index) => {
return myArray[index]
})
})

Extracting a field value from a nested array of arrays with objects

Been trying to extract values from fields with no luck. Tried using the map function by nesting it, as well as concating the fields to try and achieve my result but with no luck.
I am looking to take an object with an almost identical structure to this:
[{
name: 'sean',
age: 26,
address:
[{
street: 'red'
},
{
street: 'blue'
}]
}];
From this structure, I want to be able to extract the street value and insert it into a new array. So the result should be:
const newArray = ['red', 'blue'];
The address field can have multiple objects inside of it, so the solution is able to scale for 1-to-many.
const input = [
{
name: 'sean',
age: 26,
address: [
{street: 'red'},
{street: 'blue'}
]
},
{
name: 'foo',
age: 1,
address: [
{street: 'yellow'},
{street: 'green'}
]
}
];
const newArray = input.flatMap(({address}) => address.map(({street}) => street));
console.log(newArray);
Array.prototype.flatMap takes a callback function returning an array of values, and then returns an array of all the values inside the arrays returned by the callback. In other words, array.flatMap(callback) is semantically equivalent to array.map(callback).flat().
You mentioned trying to use reduce and concat in your comment. However, according to the MDN documentation:
var arr = [1, 2, 3, 4];
arr.flatMap(x => [x, x * 2]);
// is equivalent to
arr.reduce((acc, x) => acc.concat([x, x * 2]), []);
// [1, 2, 2, 4, 3, 6, 4, 8]
Note, however, that this is inefficient and should be avoided for large arrays: in each iteration, it creates a new temporary array that must be garbage-collected, and it copies elements from the current accumulator array into a new array instead of just adding the new elements to the existing array.

Create a sorted array by mistake using .map()

I tried to make something that works as Set() using a couple tools that I learned. It worked, but I noticed a bug: it sorted my array! Can explain me someone why, please?
Here's my code:
function uniteUnique(...arr) {
let array = arr.flat()
let newArr = [];
console.log(array) // [ 1, 3, 2, 5, 2, 1, 4, 2, 1 ]
let myMap = array
.map(elem => {
if (!newArr.includes(elem))
return newArr.push(elem)
})
.filter(Boolean)
console.log(myMap) // [ 1, 2, 3, 4, 5 ]
}
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
I know that for you might be too simple, but I ask so I can understand what is happening here.
console.log(myMap) // [ 1, 2, 3, 4, 5 ]
The result of your log is the number of pushed elements but accidentally, you thought they are sorted.
Also, if you return the mapped list you will end up with an array that contains an integer and boolean values. Instead of this, you need to return newArr.
Your code will be like this :
function uniteUnique(...arr) {
let flattedArray = arr.flat()
let set = [];
flattedArray.forEach(elem => !set.includes(elem) && set.push(elem))
return set
}
const set = uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
console.log(set)
in your code MyMap holds your newArr length as array.push returns the length of your array
so every time it returns the count:
for example if you tried to run this code
let newArr = []
console.log(newArr.push(20)) // the output is 1
and that's what your myMap holds => the length of your newArr
so if you want the filtered array you should use newArr
let array = [ 1, 3, 2, 5, 2, 1, 4, 2, 1 ]
let newArr = [];
let myMap = array.map(elem => {
if (!newArr.includes(elem))
return newArr.push(elem)
}).filter(Boolean)
console.log(newArr) //[1, 3, 2, 5, 4]

Convert array into different structure using array values

Is there a simple way to get the latter array from the former?
Source array :
[1, 2, 3, 4, 5]
Target structure:
[
{id: 1, text: idToName(1)},
{id: 2, text: idToName(2)},
{id: 3, text: idToName(3)},
{id: 4, text: idToName(4)},
{id: 5, text: idToName(5)}
]
It's easy to use Array.prototype.map here:
var array = [1, 2, 3, 4, 5];
var mapped = array.map(function(num) { return { id: num, text: idToName(num) }; });
With ES6 arrow functions it would be:
let mapped = array.map(num => ({ id: num, text: idToName(num) }));
var _x = [1, 2, 3, 4, 5].map(function(v){
return {"id":v, "text":idToName(v)};
});
Use .map, Live Fiddle
Or in ES6
var _x = [1, 2, 3, 4, 5].map(v => ({"id":v, "text":idToName(v)}));
Live Fiddle

Creating javascript object without fieldname

Hi I'm trying to create an object in JS which is like this
{'0':{1,2,3,4},'1':{1,2,3,4}, '2':{1,2,3,4}}
but I don't know how to create the {1,2,3,4} part.
These objects have to be created from something this :
[{'value': '{1,2,3,4,5}', 'id': 0, 'type':'node'}]
here is how I do it for the fieldname:
var domain={};
nodes.forEach(function(node){
if(node.type == "node")
domain[node.id]= node.value;
});
but node.value gives me String I don't want it to be string. I want to be in the form of {1,3,4.5}.
I appreciate any help
All properties of an object must have a name. However, you can use an array instead (note that to be truly considered JSON, the property names must be double-quoted string literals):
var myObj = {
"0": [1, 2, 3, 4],
"1": [1, 2, 3, 4],
"2": [1, 2, 3, 4]
};
In fact the, whole object can be expressed as a 2-dimensional array:
var myObj = [ [1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4] ];
And you can access it's values like this:
myObj[1][2]; // 3

Categories