Related
I am receiving a list of comments from a graphql backend in the following format:
[
{
"__typename": "Comment",
"id": "1",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "test 1"
},
{
"__typename": "Comment",
"id": "2",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "this is a comment"
},
{
"__typename": "Comment",
"id": "34",
"userId": "1",
"postId": "1",
"parentCommentId": "1",
"content": "reply to test1"
},
{
"__typename": "Comment",
"id": "35",
"userId": "1",
"postId": "1",
"parentCommentId": "34",
"content": "nested reply to \"reply to test1\"\n\n"
},
{
"__typename": "Comment",
"id": "36",
"userId": "1",
"postId": "1",
"parentCommentId": "34",
"content": "test?"
}
]
The comments with parentCommentId === null are the highest level comments, while comments where parentCommentId !== null are replies to a comment where id === parentCommentId
I would like to transform this data structure to something like:
[{
"__typename": "Comment",
"id": "1",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "test1",
"replies": [{
"__typename": "Comment",
"id": "34",
"userId": "1",
"postId": "1",
"parentCommentId": "1",
"content": "reply to test1",
"replies": [{
"__typename": "Comment",
"id": "35",
"userId": "1",
"postId": "1",
"parentCommentId": "34",
"content": "reply to test1"
}]
}]
},
{
"__typename": "Comment",
"id": "2",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "this is a comment",
"replies": []
}
]
I have the following function to do the data transformation:
function formatData(comments: Array < IComment > ) {
let commentList = Array < IComment > ();
// add comments without `parentCommentId` to the list.
// these are top level comments.
for (let i = 0; i < comments.length; i++) {
if (!comments[i].parentCommentId) {
commentList.push({ ...comments[i],
replies: []
});
}
}
for (let i = 0; i < comments.length; i++) {
if (comments[i].parentCommentId) {
const reply = comments[i];
mapReplyToComment(commentList, reply);
}
}
return commentList;
function mapReplyToComment(
commentList: Array < IComment > ,
reply: IComment
): any {
return commentList.map((comment) => {
if (!comment.replies) {
comment = { ...comment,
replies: []
};
}
if (comment.id === reply.parentCommentId) {
comment.replies.push(reply);
return comment;
} else {
return mapReplyToComment(comment.replies, reply);
}
});
}
}
However this only works for one level deep into the object tree. so I am getting the replies of a main comment, but replies to replies are not added to the object.
this is what I am getting now:
[{
"__typename": "Comment",
"id": "1",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "test1",
"replies": [{
"__typename": "Comment",
"id": "34",
"userId": "1",
"postId": "1",
"parentCommentId": "1",
"content": "reply to test1"
// -- I should have here another node of "replies"
}]
},
{
"__typename": "Comment",
"id": "2",
"userId": "1",
"postId": "1",
"parentCommentId": null,
"content": "this is a comment",
"replies": []
}
]
Could you please point out what am I doing wrong and provide some explanation?
Thanks in advance
Edit:
based on #Nina Scholz's comment I came up with this solution:
function formatData(data: Array < IComment > , root: string) {
const temp: any = {};
data.forEach((comment: IComment) => {
const parentCommentId = comment.parentCommentId ? ? root;
if (temp[parentCommentId] == null) {
temp[parentCommentId] = {};
}
if (temp[parentCommentId].replies == null) {
temp[parentCommentId].replies = [];
}
if (temp[comment.id] == null) {
temp[parentCommentId].replies.push(
Object.assign((temp[comment.id] = {}), comment)
);
} else {
temp[parentCommentId].replies.push(
Object.assign(temp[comment.id], comment)
);
}
});
return temp[root].replies;
}
You could take a single iteration with the help of an object which keeps the references of parent to children and children to parent.
const
getTree = (data, root) => {
const t = {};
data.forEach(o =>
((t[o.parentCommentId] ??= {}).replies ??= []).push(
Object.assign(t[o.id] ??= {}, o)
)
);
return t[root].replies;
},
data = [{ __typename: "Comment", id: "1", userId: "1", postId: "1", parentCommentId: null, content: "test 1" }, { __typename: "Comment", id: "2", userId: "1", postId: "1", parentCommentId: null, content: "this is a comment" }, { __typename: "Comment", id: "34", userId: "1", postId: "1", parentCommentId: "1", content: "reply to test1" }, { __typename: "Comment", id: "35", userId: "1", postId: "1", parentCommentId: "34", content: "nested reply to \"reply to test1\"\n\n" }, { __typename: "Comment", id: "36", userId: "1", postId: "1", parentCommentId: "34", content: "test?" }],
tree = getTree(data, null);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Since the other answer was hard to understand for me, I will post mine as well which splits the steps into standalone functions:
(Note that I added the replies array in your sample data)
let data = [{ "__typename": "Comment", "id": "1", "userId": "1", "postId": "1", "parentCommentId": null, "content": "test 1", "replies": [] },
{ "__typename": "Comment", "id": "2", "userId": "1", "postId": "1", "parentCommentId": null, "content": "this is a comment", "replies": [] },
{ "__typename": "Comment", "id": "34", "userId": "1", "postId": "1", "parentCommentId": "1", "content": "reply to test1", "replies": [] },
{ "__typename": "Comment", "id": "35", "userId": "1", "postId": "1", "parentCommentId": "34", "content": "nested reply to \"reply to test1\"\n\n", "replies": [] },
{ "__typename": "Comment", "id": "36", "userId": "1", "postId": "1", "parentCommentId": "34", "content": "test?", "replies": [] }
]
function findLowestComment(dataArray) {
for (let i = 0; i < dataArray.length; i++) {
let comment = dataArray[i]
isLowest = true
if (comment.parentCommentId == null) {
continue
}
for (let j = 0; j < dataArray.length; j++) {
if (dataArray[j].id != comment.id &&
dataArray[j].parentCommentId == comment.id &&
dataArray[j].parentCommentId != null) {
isLowest = false;
break
}
}
if (isLowest) {
return i
}
}
}
function insertIntoParent(dataArray, commentIndex) {
for (let j = 0; j < dataArray.length; j++) {
if (dataArray[j].id == dataArray[commentIndex].parentCommentId) {
dataArray[j].replies.push(dataArray[commentIndex])
dataArray.splice(commentIndex, 1)
break
}
}
}
function mapComments(dataArray) {
for (let j = 0; j < dataArray.length; j++) {
let lowestIndex = findLowestComment(dataArray)
insertIntoParent(dataArray, lowestIndex)
}
}
mapComments(data)
console.log(JSON.stringify(data, undefined, 2))
Problem:
I am working on a mini project involving a JSON file and express/nodejs and I am stuck on a portion that contains the following instructions:
Using a post route, determine the user's most compatible friend using
the following rules: Convert each user's results into a simple array
of numbers.
Compare the difference between current user's scores against those
from potential matches, question by question. Add up the differences
to calculate the totalDifference.
Example: User 1: [5, 1, 4, 4, 5, 1, 2, 5, 4, 1] User 2: [3, 2, 6, 4,
5, 1, 2, 2, 4, 1]
Total Difference: 2 + 1 + 2 + 3 = 8
Remember to use the absolute value of the differences; no negative
results! Your app should calculate both 5-3 and 3-5 as 2, etc.
I am able to get the results that look like this (the submitted array is the last array all 5's):
Here is the portion of code I am using for that:
app.post('/surveyResponse', function(req,res){
let photo = req.body.url;
let name = req.body.name;
let travel = req.body.travel;
let affection = req.body.affection;
let family = req.body.family;
let fitness = req.body.fitness;
let movie = req.body.movie;
let education = req.body.education;
let career = req.body.career;
let marriage = req.body.marriage;
let children = req.body.children;
let pets = req.body.pets;
let sum = 0;
let obj = {};
let person = {
name: name,
photo: photo,
scores: [
travel,
affection,
family,
fitness,
movie,
education,
career,
marriage,
children,
pets
]
}
//finding the sum of all the numbers
for(i in person.scores){
sum+=Number(person.scores[i]);
}
//form submission results
let score = person.scores;
// Read the file and send to the callback
fs.readFile('./app/data/friends.json', handleFile)
// Write the callback function
function handleFile(err, data) {
if (err) throw err
obj = JSON.parse(data)
for(var key in obj){
var obj2 = obj[key];
console.log(obj2.scores);
}
//this is the console.log for my form submission array
console.log(score);
}
//------------------------------------
// result that prints out on the HTML
res.send('Your name is ' + name + ' You Score is ' + sum );
});
GOAL
The goal is the find the user with the least difference between their results and what the user submitted.
RESEARCH
I have done research How to compare each object in an array with each other. When found update the object with a new property How to Subtract Multiple Objects from an Array with Another array
and most of the examples deal with having separate JSON objects and comparing them to each other and the one I found that compared an array of JSON objects was just comparing phone numbers. I am stuck on my next steps. I just need a jump start/guidance please.
Here is the JSON file I am working with:
[
{
"name": "Mike Jackson",
"photo": "./app/public/matchPhotos/photo0.jpg",
"scores": [
"3",
"2",
"4",
"3",
"3",
"4",
"4",
"4",
"3",
"4"
]
},
{
"name": "Jermaine Subia",
"photo": "./app/public/matchPhotos/photo1.jpg",
"scores": [
"4",
"4",
"2",
"2",
"4",
"5",
"3",
"4",
"5",
"2"
]
},
{
"name": "Taji Gibson",
"photo": "./app/public/matchPhotos/photo2.jpg",
"scores": [
"1",
"5",
"3",
"2",
"3",
"1",
"3",
"4",
"3",
"3"
]
},
{
"name": "Jamie Schully",
"photo": "./app/public/matchPhotos/photo3.jpg",
"scores": [
"5",
"3",
"3",
"4",
"2",
"4",
"4",
"5",
"5",
"5"
]
},
{
"name": "Justin Andres",
"photo": "./app/public/matchPhotos/photo4.jpg",
"scores": [
"2",
"1",
"1",
"1",
"2",
"3",
"2",
"2",
"2",
"4"
]
},
{
"name": "Austin Brooks",
"photo": "./app/public/matchPhotos/photo5.jpg",
"scores": [
"2",
"3",
"4",
"2",
"4",
"4",
"4",
"4",
"5",
"4"
]
},
{
"name": "Jessica Jones",
"photo": "./app/public/matchPhotos/photo6.jpg",
"scores": [
"4",
"4",
"4",
"4",
"4",
"4",
"4",
"4",
"5",
"4"
]
},
{
"name": "Jasmine Love",
"photo": "./app/public/matchPhotos/photo7.jpg",
"scores": [
"4",
"3",
"3",
"2",
"2",
"2",
"2",
"1",
"2",
"1"
]
},
{
"name": "Sandra Smith",
"photo": "./app/public/matchPhotos/photo8.jpg",
"scores": [
"1",
"2",
"2",
"2",
"4",
"3",
"4",
"3",
"3",
"1"
]
},
{
"name": "Kevin Hart",
"photo": "./app/public/matchPhotos/photo9.jpg",
"scores": [
"5",
"5",
"3",
"3",
"2",
"2",
"5",
"5",
"4",
"3"
]
}
]
UPDATE 1
I am trying to incorporate the following code but am not understanding as to why I keep getting the following error:
ReferenceError: data is not defined
I believe it has to do with how I am trying to incorporate the incoming data. I took the code and tried to translate it to fit my code.
// Read the file and send to the callback
fs.readFileSync('./app/data/friends.json', findCompatibility); <---- This is the line I think is causing issues
// Write the callback function
function findCompatibility(data) {
var results = [];
for (let i = 0; i < data.length; i++) {
for (let j = 1; j < data.length - 1; j++) {
const user1 = data[i];
const user2 = data[j];
var difference = 0;
for (let k = 0; k < user1.scores.length; k++) {
difference += Math.abs(Number(user1.scores[k]) - Number(user2.scores[k]));
}
results.push({"name": user1.name, "friend": user2.name, "difference": difference});
}
}
return results;
}
console.log(findCompatibility(data));
Some pointers to point you in right direction:
To ensure that differences aren't negative use Math.abs() to get the absolute value of the difference.
Right now all the scores are strings, convert them to number using Number() or parseInt().
var data = [ { "name": "Mike Jackson", "photo": "./app/public/matchPhotos/photo0.jpg", "scores": [ "3", "2", "4", "3", "3", "4", "4", "4", "3", "4" ] }, { "name": "Jermaine Subia", "photo": "./app/public/matchPhotos/photo1.jpg", "scores": [ "4", "4", "2", "2", "4", "5", "3", "4", "5", "2" ] }, { "name": "Taji Gibson", "photo": "./app/public/matchPhotos/photo2.jpg", "scores": [ "1", "5", "3", "2", "3", "1", "3", "4", "3", "3" ] }, { "name": "Jamie Schully", "photo": "./app/public/matchPhotos/photo3.jpg", "scores": [ "5", "3", "3", "4", "2", "4", "4", "5", "5", "5" ] }, { "name": "Justin Andres", "photo": "./app/public/matchPhotos/photo4.jpg", "scores": [ "2", "1", "1", "1", "2", "3", "2", "2", "2", "4" ] }, { "name": "Austin Brooks", "photo": "./app/public/matchPhotos/photo5.jpg", "scores": [ "2", "3", "4", "2", "4", "4", "4", "4", "5", "4" ] }, { "name": "Jessica Jones", "photo": "./app/public/matchPhotos/photo6.jpg", "scores": [ "4", "4", "4", "4", "4", "4", "4", "4", "5", "4" ] }, { "name": "Jasmine Love", "photo": "./app/public/matchPhotos/photo7.jpg", "scores": [ "4", "3", "3", "2", "2", "2", "2", "1", "2", "1" ] }, { "name": "Sandra Smith", "photo": "./app/public/matchPhotos/photo8.jpg", "scores": [ "1", "2", "2", "2", "4", "3", "4", "3", "3", "1" ] }, { "name": "Kevin Hart", "photo": "./app/public/matchPhotos/photo9.jpg", "scores": [ "5", "5", "3", "3", "2", "2", "5", "5", "4", "3" ] } ];
function findCompatibility(data) {
var results = [];
for (let i = 0; i < data.length; i++) {
for (let j = 1; j < data.length - 1; j++) {
const user1 = data[i];
const user2 = data[j];
var difference = 0;
for (let k = 0; k < user1.scores.length; k++) {
difference += Math.abs(Number(user1.scores[k]) - Number(user2.scores[k]));
}
results.push({"name": user1.name, "friend": user2.name, "difference": difference});
}
}
return results;
}
console.log(findCompatibility(data));
var arr1 = [1,4,7,88,40];
var arr2 = [1,77,3,45];
function diff(a1, a2){
var s1 = a1.reduce((red,n) => red+n);
var s2 = a2.reduce((red,n) => red+n);
var total = s1 - s2;
return total >= 0 ? total : -1*total;
}
console.log(diff(arr2, arr1));
This question already has answers here:
How can I remove a specific item from an array in JavaScript?
(142 answers)
Closed 5 years ago.
This Object:
var Betreiber = {
"user1": [
{
"desc": "60",
"Id": 3473631702,
"Status": "offline"
},
{
"desc": "61",
"Id": 3473631703,
"Status": "offline"
}
],
"user2": [
{
"desc": "62",
"Id": 963346121,
"Status": "offline"
},
{
"desc": "63",
"Id": 963346122,
"Status": "offline"
}
],
"user3": [
{
"desc": "64",
"Id": 972878784
},
{
"desc": "65",
"Id": 3473631706,
"Status": "offline"
}
]
}
My code:
var anlagen = [963346121, 963346122];
for(var users in Betreiber) {
for(var k=0;k<anlagen.length; k++) {
for(var ids in Betreiber[users]) {
if(anlagen[k] != Betreiber[users][ids].Id ){
delete Betreiber[users][ids];
}
}
}
if(Betreiber[users].length === 0) {
delete Betreiber[users];
}
}
i want to splice / delete every Element that doesn't fit my anlagen Array.
For some reason, the Elements are removed, but not completely deleted.
For Example: If i only want to keep the values of user1:
State: user1: [ , ], user2: [ , ], user3: [ , ]
Desired: user1: [data....]
If the user.length is 0, i wan't to delete the whole user.
I think this is what you want:
var Betreiber = {
"user1": [{
"desc": "60",
"Id": 3473631702,
"Status": "offline"
},
{
"desc": "61",
"Id": 3473631703,
"Status": "offline"
}
],
"user2": [{
"desc": "62",
"Id": 963346121,
"Status": "offline"
},
{
"desc": "63",
"Id": 963346122,
"Status": "offline"
}
],
"user3": [{
"desc": "64",
"Id": 972878784
},
{
"desc": "65",
"Id": 3473631706,
"Status": "offline"
}
]
};
var anlagen = [963346121, 963346122];
Object.keys(Betreiber).forEach(key => {
Betreiber[key] = Betreiber[key].filter(item => {
return anlagen.indexOf(item.Id) !== -1;
});
if(!Betreiber[key].length) {
delete Betreiber[key];
}
});
console.log(Betreiber);
You can just filter the element out which don't meet your criteria using Array#filter. And if the resultant array is of length 0, you can delete its key from the object.
var anlagen = [963346121, 963346122];
for(var user in Betreiber) {
for (var k = 0, len = anlagen.length; k < len; k++) {
for (var j = 0, _len = Betreiber[user].length; j < _len; j++) {
if (anlagen[k] != Betreiber[user][j].Id ) {
Betreiber[user].splice(j, 1);
}
}
}
if (Betreiber[user].length === 0) {
delete Betreiber[user];
}
}
I have an object type as below:
{
"1": {
"ref": "1",
"active": "1",
"showorder": "1",
"title": "Test 1"
},
"2": {
"ref": "2",
"active": "1",
"showorder": "2",
"title": "Test 2"
},
"3": {
"ref": "3",
"active": "1",
"showorder": "4",
"title": "Test 4"
},
"4": {
"ref": "4",
"active": "1",
"showorder": "9",
"title": "Test 9"
},
"5": {
"ref": "5",
"active": "1",
"showorder": "7",
"title": "Test 7"
}
}
On the basis of showorder property i need it to be arranged as follows:
{
"1": {
"ref": "1",
"active": "1",
"showorder": "1",
"title": "Test 1"
},
"2": {
"ref": "2",
"active": "1",
"showorder": "2",
"title": "Test 2"
},
"3": {
"ref": "3",
"active": "1",
"showorder": "3",
"title": "Test 3"
},
"4": {
"ref": "4",
"active": "1",
"showorder": "4",
"title": "Test 4"
},
"5": {
"ref": "5",
"active": "1",
"showorder": "5",
"title": "Test 5"
}
}
And here is my failed attempt thought i would pass the object to this function :
function reArrangeTilesObject(tilesObj){
var newObj = [];
for(var i in tilesObj){
var j = 1;
if(j == tilesObj[i].showorder){
newObj.push(tilesObj[i]);
j++;
}
}
return newObj;
}
Sorry if i am being unclear. The object is created in a random manner. So what i want is the object to be arranged as per the showorder property. so if showorder is 4 it should come in the key of 4 and not have the object of showorder 9. showorder 9 should come under the key of 9. Thanks
Steps:
Convert the object to an array (objects are unordered, arrays are ordered)
Sort the array
Code:
function reArrangeTilesObject(tilesObj) {
var tilesArray = [];
// Step 1 - convert to array
for (var i in tilesObj) {
tilesArray.push(tilesObj[i]);
}
// Step 2 - sort
tilesArray.sort(function(a, b) {
return a.showorder - b.showorder;
});
return tilesArray;
}
Result – an ordered array:
[
{"ref":"1","active":"1","showorder":"1","title":"Test 1"},
{"ref":"2","active":"1","showorder":"2","title":"Test 2"},
{"ref":"3","active":"1","showorder":"4","title":"Test 4"},
{"ref":"5","active":"1","showorder":"7","title":"Test 7"},
{"ref":"4","active":"1","showorder":"9","title":"Test 9"}
]
I may have misunderstood something but :
for (var i = 0; i < tilesObj; i++)
{
tilesObj[i].showOrder = i;
tilesObj[i].title = "Test "+i;
}
or
for (var i in tilesObj)
{
tilesObj[i].showOrder = tilesObj[i].ref;
tilesObj[i].title = "Test "+tilesObj[i].ref;
}
will do the job on the example I believe.
I can't quite understand if you're trying to rename the properties in the object array, or sort them into a new array.
If you're trying to sort:
function reArrangeTilesObject(tilesObj) {
var newObj = [];
for (var i = 1; i <= tilesObj.length; i++) {
for (var j in tilesObj) {
if (i == tilesObj[j].showorder) {
newObj.push(tilesObj[j]);
break;
}
}
}
return newObj;
}
Should add them to your newObj array based on their showorder property.
Try this one (demo):
function reArrangeTilesObject(tilesObj){
var result = {};
for(var key in tilesObj){
content = result[key] = tilesObj[key];
content.showorder = key;
content.title = "Test " + key;
}
return result;
}
It will return a new object in the original format (a Dictionary).
If you want to return an Array (and deal with possible empty indexes), just change var result = {}; into var result = [];
If you are just rewriting the showorder and title values this will work
function fix(o) {
for(var n in o) {
o[n].showorder = n;
o[n].title = "Test " + n;
}
}
In javascript/jquery how do i achieve following
old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
Using jquery iterate over the above and change to following
new_dataset = [
{
"dob":"xyz",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
},{
"dob":"er",
"name": <first and last name values>
"start_date":<value of month day year>,
"children": [ {
child_id :1,
child_id : 2
},
]
}]
If someone can give the code to transform the data it would help me to understand the iteration
You could do something like:
function transformDataset(oldDataset) {
var newDataset = [];
var newObj;
for (var i = 0; i < oldDataset.length; i++) {
newObj = transformObj(oldDataset[i]);
newDataset.push(newObj);
}
return newDataset;
}
function transformObj(obj) {
var children = obj.children;
obj.name = obj.name.first + ' ' + obj.name.last;
obj.start_date = obj.start_date.month + ' ' + obj.start_date.day + ' ' + obj.start_date.year;
obj.children = [];
for (var i = 0; i < children.length; i++) {
obj.children.push(children[i].child.id);
}
return obj;
}
var new_dataset = transformDataset(old_dataset);
Note that new_dataset will have an array of child id instead of an object with multiple child_id properties.
You also had a typo in old_dataset.start_date.month (was written moth)(or maybe that was intentional).
use map first to iterate the array data (old_dataset), replace element name & start_date with new value then return the array
const old_dataset = [
{
"dob": "xyz",
"name": {
"first": " abc",
"last": "lastname"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
},
{
"dob": "er",
"name": {
"first": " abc",
"last": "txt"
},
"start_date": {
"moth": "2",
"day": "5",
"year": 1
},
"children": [
{
"child": {
"id": "1",
"desc": "first child"
}
},
{
"child": {
"id": "2",
"desc": "second child"
}
}
]
}
]
let new_dataset = old_dataset.map((arr) => {
arr.name = `${arr.name.first} ${arr.name.last}`
arr.start_date = `${arr.start_date.moth} ${arr.start_date.day} ${arr.start_date.year}`
return arr
})
console.log(new_dataset)