run console one time inside map function using javascript / node js [closed] - javascript

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I have an array and I want to store its variable in files as I have declare files outside the map function
let object = [
{
id: '01',
name: 'Subject',
'Data.type': 'maths',
},
{
id: '02',
name: null,
'Data.type': 'science',
},
{
id: '04',
name: 'language',
'Data.type': 'node',
},
{
id: '05',
name: null,
'Data.type': 'node',
},{
id: '01',
name: 'Subject',
'Data.type': 'maths',
},
{
id: '02',
name: 'Subject',
'Data.type': 'science',
},
{
id: '04',
name: null,
'Data.type': 'node',
},
{
id: '05',
name: null,
'Data.type': 'node',
}
];
let names=[];
object.map((value) => {
if(typeof value.name === "string"){
names.push(value.name);
console.log(names);
}
//some code here
//code here
// use of names to perform some task
})
the value is printed like this
["subject"]
["subject",
"language"]
["subject",
"language",
"subject"]
["subject",
"language",
"subject",
"subject"]
is there any possibility it should only run 1 time inside map function with fully loaded value inside like this so i can perform task inside the map function
files= ["subject",
"language",
"subject",
"subject"]

Array.prototype.map():
The purpose of array.map is to create a new array where each element is changed to the result of the original element gone through the provided function.
For example,
var a = [1, 2, 3];
function times2(n) {
return n * 2;
}
var b = a.map(times2);
console.log(b); // Will log [2, 4, 5]
Array.prototype.forEach():
There is also the function array.forEach. The purpose of this is to run a function with each element of the array as an input in order.
For example,
a = [1, 2, 3];
a.forEach(console.log); // Will log: "1", then "2", then "3".
Your solution:
You are wanting to run a function on each element of your array.
Your function should take one element as an input, and push it to another existing array.
You should wait until every element has been added to the new array to log it.
For example,
let names = [];
function addToNames(element) {
if (typeof element.name === "string") {
names.push(element.name);
}
}
object.forEach(addToNames);
console.log(names);
// Now that names array is complete, you can do whatever you need with it.
Another option, using arrow functions,
let names = [];
object.forEach(element => {
if (typeof element.name === "string") {
names.push(element.name);
}
});
console.log(names);
// Now that names array is complete, you can do whatever you need with it.

Related

ES6 reduce function affecting array outside of scope

I've rewritten this into a simplified form to demonstrate, I have an array of pickers who have an array of time entries, I'm using reduce to summarise time entries by type on the pickers & then a second reduce to show global entries across both pickers.
The first reduce per picker works as expected.
The second reduce on global time entries works as expected but somehow changes the entries for the first picker ( Sam ).
Sam & John pick the same amount.
Apples 2h, Peaches 2h, Lemons 1h
Is there a better way to write this? Is there a concept I've failed to understand?
function testBug() {
// Reducer Function
function entryReducer(summary, entry) {
// find an index if the types of fruit are the same
let index = summary.findIndex((item) => {
return item.type.id === entry.type.id;
});
if (index === -1) {
summary.push(entry);
} else {
summary[index].hours = summary[index].hours + entry.hours;
}
return summary;
}
let pickers = [
{
id: 1,
identifier: "Sam Smith",
timeEntries: [
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
{
type: {
id: 3,
name: "Lemons",
},
hours: 1,
},
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
],
},
{
id: 2,
identifier: "John Snow",
timeEntries: [
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
{
type: {
id: 3,
name: "Lemons",
},
hours: 1,
},
{
type: {
id: 1,
name: "Apples",
},
hours: 1,
},
{
type: {
id: 2,
name: "Peaches",
},
hours: 1,
},
],
},
];
let pickersSummary = [];
let timeEntriesSummary = [];
for (const picker of pickers) {
if (picker.timeEntries.length > 0) {
// reduce time entries into an array of similar types
picker.timeEntries = picker.timeEntries.reduce(entryReducer, []);
// push to pickers summary arr
pickersSummary.push(picker);
// push time entries to a summary array for later reduce
picker.timeEntries.map((entry) => timeEntriesSummary.push(entry));
}
}
// Reduce time entries for all pickers
// Sam & John pick the same amount
// Apples 2h
// Peaches 2h
// Lemons 1h
// **** If I run this Sam's entries are overwritten with the global time entries ***
timeEntriesSummary = timeEntriesSummary.reduce(entryReducer, []);
const results = { pickersSummary, timeEntriesSummary };
console.log(results);
}
testBug();
module.exports = testBug;
Even though with each reducer you pass a new array [], the actual objects contained by these arrays could be shared. This means when you edit one of the objects in array "A", the objects could also change in array "B".
You know how some languages let you pass variables by value or by reference and how this fundamentally changes how values are handled? JavaScript technically uses call-by-sharing. I suggest reading this other answer: Is JavaScript a pass-by-reference or pass-by-value language?
once an element in an array is pushed into a different array it is separate in memory?
No, it isn't. In JavaScript you will always remember when you made an individual copy of an object (or at least wanted to), because that needs some effort, see What is the most efficient way to deep clone an object in JavaScript? or How do I correctly clone a JavaScript object?
So, just like when you use a=b, push(a) into an array refers the original object. See this example where there is a single object accessible via two variables (x and y), and via both elements of array z. So modifying it as z[1] affects all the others:
let x={a:5};
let y=x;
let z=[x];
z.push(y);
z[1].a=4;
console.log(x);
console.log(y);
console.log(z[0]);
console.log(z[1]);
As your objects are value-like ones and do not have anything what JSON would not support (like member functions), JSON-based cloning can work on them:
function testBug() {
// Reducer Function
function entryReducer(summary, entry) {
// find an index if the types of fruit are the same
let index = summary.findIndex((item) => {
return item.type.id === entry.type.id;
});
if (index === -1) {
//summary.push(entry);
summary.push(JSON.parse(JSON.stringify(entry))); // <--- the only change
} else {
summary[index].hours = summary[index].hours + entry.hours;
}
return summary;
}
let pickers = [
{id: 1, identifier: "Sam Smith", timeEntries: [
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},
{type: {id: 3, name: "Lemons",}, hours: 1,},
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},],},
{id: 2, identifier: "John Snow", timeEntries: [
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},
{type: {id: 3, name: "Lemons",}, hours: 1,},
{type: {id: 1, name: "Apples",}, hours: 1,},
{type: {id: 2, name: "Peaches",}, hours: 1,},],},];
let pickersSummary = [];
let timeEntriesSummary = [];
for (const picker of pickers) {
if (picker.timeEntries.length > 0) {
// reduce time entries into an array of similar types
picker.timeEntries = picker.timeEntries.reduce(entryReducer, []);
// push to pickers summary arr
pickersSummary.push(picker);
// push time entries to a summary array for later reduce
picker.timeEntries.map((entry) => timeEntriesSummary.push(entry));
}
}
// Reduce time entries for all pickers
// Sam & John pick the same amount
// Apples 2h
// Peaches 2h
// Lemons 1h
// **** If I run this Sam's entries are overwritten with the global time entries ***
timeEntriesSummary = timeEntriesSummary.reduce(entryReducer, []);
const results = { pickersSummary, timeEntriesSummary };
console.log(results);
}
testBug();
Now it probably displays what you expected, but in the background it still alters the pickers themselves, you have that picker.timeEntries = ... line running after all. It may be worth mentioning that const something = xy; means that you can not write something = yz; later, something will stick with a given entity. But, if that entity is an object, its internals can still be changed, that happens with picker.timeEntries above (while writing picker = 123; would fail).

Filter an array of objects with a second array with multiple values

I am trying to write a function to take the first object in the "parent" array, pull out the child field (which is in that array) and use that field to filter the second object called "child".
I want to get all the related records from the child object that are in the child field in the parent object.
Expected output
child: [
{
**id: 1,**
name: 'Jimmy Yukka',
},
{
**id: 2,**
name: 'Up North',
}
INPUT
Parent: [
{
**id: 1,**
name: 'Melbourne Bands',
**child: [1, 2]**
}
I have the following data
Parent: [
{
**id: 1,**
name: 'Melbourne Bands',
**child: [1, 2]**
},
{
id: 2,
name: 'Sydney Bands',
child: [3]
}
],
child: [
{
**id: 1,**
name: 'Jimmy Yukka',
},
{
**id: 2,**
name: 'Up North',
},
{
id: 3,
url: 'jimmyyukka.com',
name: 'INXS',
CreatedByUserId: 1
}
],
The code of the function I have implemented so far:
currentChildrenIds(ParentId, parentData, childData) {
const singleParentRecord = parentData.filter(function(parent) {
return parent.id === ParentId;
});
const parentsChildIds = singleParentRecord[0].books;
const childRecords = childData.filter(function(child) {
return child.id === parentsChildIds
});
return childRecords
}
NOTES
This bit here is where it is wrong
const childRecords = childData.filter(function(child) {
return child.id === parentsChildIds
This bit here is also a bit rubbish (hardcoding the [0])but not I'm not sure how I should be coding it correctly
const parentsChildIds = singleParentRecord[0].books;
here,
const childRecords = childData.filter(function(child) {
return child.id === parentsChildIds
parentsChildIds is a reference to an array: you don't want to test if an id is === to a a reference,
You have to be explicit and check if the id is contained in the array:
const childRecords = childData.filter(function(child) {
return parentsChildIds.includes(child.id)
Regarding the singleParentRecord[0] that does feel weird,
since you know the method filter will always return an array of size 1 or 0,
you can use the method find instead of filter
Also in functionnal programming (array functions such as filter, map, find...)
I advice you to read a bit about the arrow function syntax because:
The syntex is more dense and it makes it easier for your brain to understand when several functions are chained
If you want to use variables which are defined outside of the function it will be available only inside of an arrow function
your code with an arrow function:
const childRecords = childData.filter((child) => {
return child.id === parentsChildIds
}
Try this:
const Parent = [
{
id: 1,
name: 'Melbourne Bands',
child: [1, 2]
},
{
id: 2,
name: 'Sydney Bands',
child: [3]
}
];
const children = [
{
id: 1,
name: 'Jimmy Yukka',
},
{
id: 2,
name: 'Up North',
},
{
id: 3,
url: 'jimmyyukka.com',
name: 'INXS',
CreatedByUserId: 1
}
];
// We create a new array with Array.map
const result = Parent.map(parent => ({
// Spread properties of the parent
...parent,
// Override the child property and filter the children array with the `includes` method
child: children.filter(child => parent.child.includes(child.id)),
}))
console.log(result);

How to check if array of object contains a string [duplicate]

This question already has answers here:
How to determine if Javascript array contains an object with an attribute that equals a given value?
(27 answers)
Closed 3 years ago.
let's say I have an array of objects:
let arr = [
{
name: 'Jack',
id: 1
},
{
name: 'Gabriel',
id: 2
},
{
name: 'John',
id: 3
}
]
I need to check whether that array includes the name 'Jack' for example using:
if (arr.includes('Jack')) {
// don't add name to arr
} else {
// push name into the arr
}
but arr.includes('Jack') returns false, how can I check if an array of objects includes the name?
Since you need to check the object property value in the array, you can try with Array​.prototype​.some():
The some() method tests whether at least one element in the array passes the test implemented by the provided function. It returns a Boolean value.
let arr = [
{
name: 'Jack',
id: 1
},
{
name: 'Gabriel',
id: 2
},
{
name: 'John',
id: 3
}
]
var r = arr.some(i => i.name.includes('Jack'));
console.log(r);

Convert array to tree

There is an array of data that needs to be converted to a tree:
const array = [{
id: 5,
name: 'vueJS',
parentId: [3]
}, {
id: 6,
name: 'reactJS',
parentId: [3]
}, {
id: 3,
name: 'js',
parentId: [1]
}, {
id: 1,
name: 'development',
parentId: null
}, {
id: 4,
name: 'oracle',
parentId: [1,2]
}, {
id: 2,
name: 'data-analysis',
parentId: null
}];
Now it works using this function:
function arrayToTree(array, parent) {
var unflattenArray = [];
array.forEach(function(item) {
if(item.parentId === parent) {
var children = arrayToTree(array, item.id);
if(children.length) {
item.children = children
}
unflattenArray.push(item)
}
});
return unflattenArray;
}
console.log(arrayToTree(array, null));
I have two problems with this feature:
The value of "parentId" should be an array of id, for example -
"parentId": [2, 3]
How to transfer to function only one argument - "array"?
https://codepen.io/pershay/pen/PgVJOO?editors=0010
I find this question confusing. It sounds like what you are really saying is the array represents the “definition of node types in the tree” and not the actual instances of those nodes that will be in the tree.
So your problem is you need to copy the “definitions” from the array to new “instance” nodes in your tree. This would let “Oracle” show twice, as you’d create a new “oracle instance” node for each parent in its parent array. It wouldn’t technically need to be a deep copy depending on your use, so you could proof of concept with Object.assign, but each instance would point to the same parents array and that may or may not cause problems for that or future reference values you add to the definition.
Finally, depending on the size of the tree and what you are really trying to do, you might want to convert to a tree represented by nodes/edges instead of parent/children. For really large datasets recursion can sometimes cause you problems.
Sorry I’m on my phone so some things are hard to see on the codepen.

combo of async map, recursion and callback in function- nodejs

I have a function which computes a value and after the computation returns value with a callback to a another function.
The situation is starting to get pretty mixed where I have 2 nested for loops and recursion inside this.
Error is: uncaughtException: Callback was already called.
First let me write the sample of the code.
functionTest (array, function (err, result) {
if (err) {
nresponse.error(err);
} else {
nresponse.success(res, result);
}
);
function dependicies(array, callback) {
async.map(array, function(item, outerNext) {
async.map(item.members, function(value, innerNext){
dependicies(array, callback);
innerNext(); //should I write this after or before the recursion call?
outerNext(); //where should I call the outerNext?
});
}, function(err, result){
**
if(err){
callback(err);
}else{
callback(null, sthComputedInMap);
}
});
}
As I write in comments, should I write innerNext after or before the recursion call? In addition to the this question, should I call outerNext after the scope of second map?
Things are pretty messed. How am I gonna clear up? I'm looking the document.
** isn't this a place where it's the end of the first async.map. I think the problem is this is called for each async.map of the recursion. What I want is to call this as break.
In code I try to loop through an array. Assume I try to get list of name fields of one document's starting from itself to its last grand grand children. The array's structure which I trace is like this;
[
{id: 1, childrenIds: [3, 4, 5], name: ""},
{id: 3, childrenIds: [8, 5], name: ""},
{id: 21, childrenIds: [ 5], name: ""},
{id: 7, childrenIds: [5], name: ""},
{id: 5, childrenIds: [], name: ""}
]
first async.map is for traversing each document, the other one is for traversing its children array.
I hope it helps :)
You can mix loops, recursion and callbacks using SynJS. Below is a working example to illustrate. setTimeout is just used as an example of asynchronous function that returns result via callback.
global.SynJS = global.SynJS || require('synjs');
function processOneDoc(modules, documents, doc, childNames) {
for(var i=0; doc.childrenIds && i < doc.childrenIds.length; i++) {
var currDoc = documents[doc.childrenIds[i]];
if(currDoc) {
childNames.push(currDoc.name);
var chNames=[];
setTimeout(function(){
SynJS.run(modules.processOneDoc, null, modules, documents, currDoc, chNames, function(){
SynJS.resume(_synjsContext);
});
if(chNames.length)
childNames.push(chNames);
},2000);
SynJS.wait();
}
}
};
function processAll(modules, documents) {
for(var d in documents) {
var childNames=[];
SynJS.run(modules.processOneDoc,null, modules, documents, documents[d], childNames,function(){
SynJS.resume(_synjsContext);
});
SynJS.wait();
console.log(new Date().toISOString(), d, childNames);
}
}
var modules = {
SynJS: SynJS,
processOneDoc: processOneDoc,
};
var documents = {
1: {id: 1, childrenIds: [3, 4, 5], name: "name of 1st"},
3: {id: 3, childrenIds: [8, 5], name: "name of 3rd"},
21: {id: 21, childrenIds: [ 5], name: "name of 21st"},
7: {id: 7, childrenIds: [5], name: "name of 7th"},
5: {id: 5, childrenIds: [], name: "name of 5th"}
};
SynJS.run(processAll,null,modules,documents,function () {
console.log('done');
});
It would produce following output:
2017-01-06T18:50:57.750Z 1 [ 'name of 3rd', [ 'name of 5th' ], 'name of 5th' ]
2017-01-06T18:50:59.785Z 3 [ 'name of 5th' ]
2017-01-06T18:50:59.800Z 5 []
2017-01-06T18:51:01.831Z 7 [ 'name of 5th' ]
2017-01-06T18:51:03.863Z 21 [ 'name of 5th' ]
done
Based on my understanding for what you have provided in your question. Your recursion call is not on the right location. One way to solve your problem is as:
function dependencies(array, callback){
outerResult = async.map(array, function(item, outerNext){
var innerResult = async.map(item.members, function(value, innerNext){
//recursive_call_condition == true
// for instance you want to check if value has an array further
if(value.members.length)
dependencies(value.members, callback);
else
innerNext(null, innerResult);
});
outerNext(null, outerResult);
}, function(err, finalResult){
// `finalResult` is your result
callback(finalResult)
});
}

Categories

Resources