Good day everyone! I have a problem with a search function on JavaScript.
This is an object I have (states):
{
"1": {
"id": "1",
"name": "Category #1",
"hasChild": "Y",
"count": "0",
"parentId": null,
"link": "/catalog/",
"subcategories": [
{
"id": "21",
"name": "Subcategory #1",
"hasChild": "Y",
"count": "0",
"parentId": "1",
"link": "/catalog/",
"subcategories": [
{
"id": "24",
"name": "subsubcategory #1",
"hasChild": "Y",
"count": "1",
"parentId": "21",
"link": "/catalog/",
"subcategories": [],
},
{
"id": "25",
"name": "subsubcategory #2",
"hasChild": "Y",
"count": "0",
"parentId": "21",
"link": "/catalog/",
"subcategories": [],
}
],
},
{
"id": "22",
"name": "Subcategory #2",
"hasChild": "Y",
"count": "0",
"parentId": "1",
"link": "/catalog/",
},
{
"id": "23",
"name": "Subcategory #3",
"hasChild": "Y",
"count": "0",
"parentId": "1",
"link": "/catalog/",
}
],
},
"2": {
"id": "2",
"name": "Category #2",
"hasChild": "Y",
"count": "0",
"parentId": null,
"link": "/catalog/",
"subcategories": [
..
],
},
}
And I have an array of products to which one has an id of the category to which it belongs. So I extracted from there only unique values of categories. It can be any level.
["24", "22", "2" ...]
My goal is to take the "name" values of parents' categories.
Example: product is in a category with id:24 (name: subsubcategory #1).
How can I get the value "Category #1" from the top category?
I use that function, but it only work for me on 1-st level (if id:1 or 2)
function filter(item, search, textKey) {
let result = []
const _filter = (item, search, textKey) => {
for (const i of item) {
if (i[textKey].indexOf(search) !== -1) {
result = [...result, { name: i.name, id: i.id, parentId: i.parentId }]
}
i.children ? _filter(i.children, search, textKey) : null
}
}
_filter(item, search, textKey)
return result
}
console.log(filter(Object.values(states), '24', 'id')) // didn't work
console.log(filter(Object.values(states), '2', 'id')) // found and mapped
I would build a function that finds the names associated with a list of ids by mapping over a function that finds the names associated with a single id. That I would build atop a function which recursively finds the full ancestor node based on an arbitrary predicate.
Your initial input is not quite a recursive structure. It looks like it might be a bad copy from console output, although it could still be legitimate. In any case, we do a transformation first, using Object .values to extract an array of actual category nodes. This could be moved from one level of the call chain to another, depending on what level of reuse you want from these functions. If your data is in fact an array, this will still work, but I would suggest replacing Object .values (states) with just states, as it makes for cleaner code.
const rootAncestor = (pred) => (xs) =>
xs .find (x => pred (x) || rootAncestor (pred) (x .subcategories || []))
const rootAncestorName = (states) => (id) =>
rootAncestor (x => x .id == id) (states) ?.name ?? ''
const rootAncestorNames = (states) => (ids) =>
ids .map (rootAncestorName (Object .values (states)))
const states = {1: {id: "1", name: "Category #1", hasChild: "Y", count: "0", parentId: null, link: "/catalog/", subcategories: [{id: "21", name: "Subcategory #1", hasChild: "Y", count: "0", parentId: "1", link: "/catalog/", subcategories: [{id: "24", name: "subsubcategory #1", hasChild: "Y", count: "1", parentId: "21", link: "/catalog/", subcategories: []}, {id: "25", name: "subsubcategory #2", hasChild: "Y", count: "0", parentId: "21", link: "/catalog/", subcategories: []}]}, {id: "22", name: "Subcategory #2", hasChild: "Y", count: "0", parentId: "1", link: "/catalog/"}, {id: "23", name: "Subcategory #3", hasChild: "Y", count: "0", parentId: "1", link: "/catalog/"}]}, 2: {id: "2", name: "Category #2", hasChild: "Y", count: "0", parentId: null, link: "/catalog/", subcategories: []}}
console .log (rootAncestorNames (states) (['24', '22', '2', '42']))
I added a failing lookup with 42 to show that I make the guess that we want to return an empty string. But at the end of rootAncestorName, you could replace that with null, undefined, or some other token.
My code's output is like this:
let myArray = [{"num": "2", "name": "Jhon"}, {"num": "1", "name": "Sara"}, {"num": "2", "name": "Domnic"}, {"num": "3", "name": "Bravo"}]
How can I access value of num in each field of the list and if num: 2, change its value to 5?
Use Array.forEach to change the original Array
let myArray = [{ "num": "2", "name": "Jhon" }, { "num": "1", "name": "Sara" }, { "num": "2", "name": "Domnic" }, { "num": "3", "name": "Bravo" }]
myArray.forEach((node) => node.num = node.num == "2" ? "5" : node.num);
console.log(myArray);
If you want to create a new array from the existing one, Use Array.map
let myArray = [{ "num": "2", "name": "Jhon" }, { "num": "1", "name": "Sara" }, { "num": "2", "name": "Domnic" }, { "num": "3", "name": "Bravo" }]
const newArray = myArray.map(({ ...node }) => node.num = node.num == "2" ? "5" : node.num);
console.log(newArray);
Please Note: Do not forget to use spread syntax ({ ...node }) else your original array will be modified here.
You could use array map:
let myArray = [{
"num": "2",
"name": "Jhon"
}, {
"num": "1",
"name": "Sara"
}, {
"num": "2",
"name": "Domnic"
}, {
"num": "3",
"name": "Bravo"
}]
const result = myArray.map(({...item}) => {
if (item.num == 2)
item.num = "5"
return item
})
console.log(result)
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));
i want to filter the given below array on the basis of dynamic values (name and section).
var allResponse = [
{
"name": "ABC",
"class": "8",
"section": "A",
},
{
"name": "DEF",
"class": "7",
"section": "B",
},
{
"name": "ABC",
"class": "8",
"section": "D",
},
]
These values of name and section, i'm getting on Click of check box.
On basis of these value , i want to filter this given array allResponse .
Values can be multiple like:
Filter the array where name is ABC and section is A and D,
Like after getting value i tried to create an object to filter like given below to filter iteratively. But not able to do it
var filterLiterals= [{"name": "ABC"},{"section": "A"},{"section": "D"}];
or
var filterLiterals= ["ABC","A","D"];
So result should be
{
"name": "ABC",
"class": "8",
"section": "A",
},
I'm confused which approach should follow to get the result.
I tried it by using || and && operator but not able to get the result what i want.
Could anybody please suggest me to suitable and proper approach to filter this array. I'm not able to do it.
Is it possible to filter in this way in javascript in any way...?
You can create a function which will accept the name and an array of section. Inside the function use filter and in the call back function return those object whose name matches and the section is included in the array of section passed to the function
var allResponse = [{
"name": "ABC",
"class": "8",
"section": "A",
},
{
"name": "DEF",
"class": "7",
"section": "B",
},
{
"name": "ABC",
"class": "8",
"section": "D",
}
]
function filterArray(name, sectionArray) {
return allResponse.filter(function(elem) {
return elem.name = name && sectionArray.includes(elem.section)
})
};
console.log(filterArray('ABC', ['A', 'D']))
If I'm reading your question correctly you want to filter your data based on what you clicked.
var allResponse = [
{
"name": "ABC",
"class": "8",
"section": "A",
},
{
"name": "DEF",
"class": "7",
"section": "B",
},
{
"name": "ABC",
"class": "8",
"section": "D",
},
];
var clickedValue = "ABC";
var filteredResponse = allResponse.filter( function(response) {
return response.name === clickedValue
});
console.log(filteredResponse);
I think this should resolve your filtering problem.
In my understanding, I need to find elements satisfying below,
name: ABC
section: A or D
var allResponse = [
{
"name": "ABC",
"class": "8",
"section": "A",
},
{
"name": "DEF",
"class": "7",
"section": "B",
},
{
"name": "ABC",
"class": "8",
"section": "D",
},
];
var filterLiterals = [
{"name": "ABC"},
{"section": "A"},
{"section": "D"}
];
const parsed = filterLiterals.reduce((acc, obj) => {
const key = Object.keys(obj)[0];
if (typeof acc[key] === 'undefined')
acc[key] = [obj[key]];
else
acc[key].push(obj[key]);
return acc;
}, {});
//console.log("parsed: ", parsed);
var answer = allResponse.filter(obj => {
let flag = true;
for (const key of Object.keys(parsed)) {
if (!parsed[key].includes(obj[key])) {
flag = false;
break;
}
}
return flag;
});
console.log(answer);
Run this!