Related
I'm trying to make a function in javascript in order to match a key and an array of objects from an API. The matching is based on 2 parameters coming from an API.
A key which is a string and an array of objects with keys and values.
The output of this match should be a new array of objects with the values where that passed key is matching with the key of that array of objects passed as a parameter.
I prepared a sample of what I'm trying to achieve but is not working as I don't know how to do it properly and below it will be moe details about it
const criteriaJson = [{
"age": {
"min": "18",
"max": "65"
},
"pain": {
"min": "5"
},
"disease": {
"valid": [
"MDD",
"PTSD"
],
"invalid": [
"None"
]
},
"medicines": "true",
"bmi": {
"min": "25",
"max": "100"
},
"weight": "90",
"gender": [
"1",
"2",
"3"
],
"pressure": "100",
"smoker": "20",
"zip": "^w+s{1}w+$"
},
{
"age": {
"min": "16",
"max": "18"
},
"pain": {
"max": "10"
},
"bmi": {
"max": "85"
},
"disease": {
"valid": [
"none"
],
"invalid": [
"PTT",
"ADT",
"OLL"
]
},
"weight": "70",
"gender": [
"1"
],
"pressure": "10"
}
]
const question = {
key: "medicines"
}
// *Matching and extracting the right criteria data for the provided question key
// *inside the criteria object
// *returns an object with the right criteria
// *doing it for every group set of rules
function questionCriteriaKeyMatch(criteriaJson, question) {
criteriaJson.map((criteria) => {
return Object.keys(criteria)
.filter((key) => {
return key === question.key;
})
.reduce((cur, key) => {
return Object.assign(cur, {
criteria: criteria[key],
});
}, {});
});
}
console.log(questionCriteriaKeyMatch(criteriaJson, question));
To explain what data we are getting that criteriaJson
This data is an array of objects which contains a set of rules divided into objects for the same item but referring to a different group.
object 1 is criteria 1 and object 2 is criteria 2 to make it simple in this specific case.
[{
"age": {
"min": "18",
"max": "65"
},
"pain": {
"min": "5"
},
"disease": {
"valid": [
"MDD",
"PTSD"
],
"invalid": [
"None"
]
},
"medicines": "true",
"bmi": {
"min": "25",
"max": "100"
},
"weight": "90",
"gender": [
"1",
"2",
"3"
],
"pressure": "100",
"smoker": "20",
"zip": "^w+s{1}w+$"
},
{
"age": {
"min": "16",
"max": "18"
},
"pain": {
"max": "10"
},
"bmi": {
"max": "85"
},
"disease": {
"valid": [
"none"
],
"invalid": [
"PTT",
"ADT",
"OLL"
]
},
"weight": "70",
"gender": [
"1"
],
"pressure": "10"
}
]
However, the cases for this data are 3 essentially
the object is empty as no criteria exist in this case from API the match with the key which doesn't exist will output null
the array has one object only so the match needs to be done on this only object and if the key does not match output null
we have an array of more than one object in this case we need to match for every single object the key and if not match output is null.
Starting with the simple case when we receive an empty array of objects
const obj = [];
const key = 'someKey';
// Output as there is no matching
[null]
Example of the second case, when we have one object in the array
const obj = [{
"age": {
"min": "18",
"max": "65"
},
"pain": {
"min": "5"
},
"disease": {
"valid": [
"MDD",
"PTSD"
],
"invalid": [
"None"
]
},
}]
// Output matching key === age -> I'm open to suggestions how this output should be for // one obj only in the array
[{
criteria: { min:"18", max:"65" }
}]
// key === pain
[{
criteria: "5"
}]
// key === disease
[{
criteria: {valid: ["MDD","PTSD"], invalid: ["None"] }
}]
// key === notExistingKey means the key we are passing to match doesn't have a match so // we output null in this case
[{ null }]
From the above example, we output the matching values with the key passed as a param, when no match then is null
The last case is the more complex probably when we have an array of objects of the criteria and this should work for an array length > 1.
Using same data as in the snippet showing what is the expected output
const criteriaJson = [{
"age": {
"min": "18",
"max": "65"
},
"pain": {
"min": "5"
},
"disease": {
"valid": [
"MDD",
"PTSD"
],
"invalid": [
"None"
]
},
"medicines": "true",
"bmi": {
"min": "25",
"max": "100"
},
"weight": "90",
"gender": [
"1",
"2",
"3"
],
"pressure": "100",
"smoker": "20",
"zip": "^w+s{1}w+$"
},
{
"age": {
"min": "16",
"max": "18"
},
"pain": {
"max": "10"
},
"bmi": {
"max": "85"
},
"disease": {
"valid": [
"none"
],
"invalid": [
"PTT",
"ADT",
"OLL"
]
},
"weight": "70",
"gender": [
"1"
],
"pressure": "10"
}
]
const key = 'medicines'
// the output should be a new array of objects as we need to compare each object to find // the key match and output every single value
// key === medicines
[
{ criteria: 'true' }, -> we have a match in the first obj
{ criteria: null }, -> we have no match in the second obj
]
// key === age
[
{ criteria: { min: "18", max: "65" }}, -> we have a match in the first obj
{ criteria: { min: "16", max: "18" }}}, -> we have a match in the second obj
]
// For the rest of the keys should follow the same logic and with more objects, we have more
// objects in the output we have
I'm adding criteria as I need that in a second phase to be able to access that obj and extract the values for further use. As the keys are not the same always as are strings from API set in a client I need a way to facilitate access to the new object by assigning a hard-coded key. That is why when there is a match I just need the values and key like criteria, so I can access without an issue the values
I started with a reduce method as I thought maybe that was the way but in the end, I'm open to new solutions as cannot figure out how to achieve my goal.
The important note is that I cannot use for loops as I have strict rules of code style which cannot change.
If will be any comment with particular questions or request will try to explain better or update my question with more relevant info.
Seems like you just want to map the array to a new array with just the values. If the key does not exist, you would just set the criteria value to null, otherwise you set the criteria to whatever the property's value is.
const criteriaJson = [{
"age": {
"min": "18",
"max": "65"
},
"pain": {
"min": "5"
},
"disease": {
"valid": [
"MDD",
"PTSD"
],
"invalid": [
"None"
]
},
"medicines": "true",
"bmi": {
"min": "25",
"max": "100"
},
"weight": "90",
"gender": [
"1",
"2",
"3"
],
"pressure": "100",
"smoker": "20",
"zip": "^w+s{1}w+$"
},
{
"age": {
"min": "16",
"max": "18"
},
"pain": {
"max": "10"
},
"bmi": {
"max": "85"
},
"disease": {
"valid": [
"none"
],
"invalid": [
"PTT",
"ADT",
"OLL"
]
},
"weight": "70",
"gender": [
"1"
],
"pressure": "10"
}
]
function getCriteria (key, data) {
if (!data?.length) return [null]
return data.map(item => ({ criteria: item[key] || null }));
}
console.log('age', getCriteria('age', criteriaJson));
console.log('medicines', getCriteria('medicines', criteriaJson));
console.log('pressure', getCriteria('pressure', criteriaJson));
This question already has answers here:
From an array of objects, extract value of a property as array
(24 answers)
Closed 1 year ago.
I have JSON content as follows
jsonList = {
"0": {
"Name": "Virat Kohli",
"Runs": "6283",
"Matches": "207",
"Average": "37.39",
"Strike Rate": "129.94",
"Half Centuries": "42",
"Centuries": "5",
"Team": "Royal Challengers Bangalore"
},
"1": {
"Name": "Shikhar Dhawan",
"Runs": "5784",
"Matches": "192",
"Average": "34.84",
"Strike Rate": "126.64",
"Half Centuries": "44",
"Centuries": "2",
"Team": "Delhi Capitals"
},
"2": {
"Name": "Rohit Sharma",
"Runs": "5611",
"Matches": "213",
"Average": "31.17",
"Strike Rate": "130.39",
"Half Centuries": "40",
"Centuries": "1",
"Team": "Mumbai Indians"
},
"3": {
"Name": "Suresh Raina",
"Runs": "5528",
"Matches": "205",
"Average": "32.51",
"Strike Rate": "136.76",
"Half Centuries": "39",
"Centuries": "1",
"Team": "Chennai Super Kings"
}
}
I get the value of "Virat Kohli" as
name = jsonList[0].Name
I am working to get all the Names in one array and Runs in one array like
names = ['Virat Kohli','Shikhar Dhawan','Rohit Sharma','Suresh Raina']
runs = [6283,5784,5611,5528]
I know I can do this using for loop. But is there any other way that is more efficient than for loop?
First, transform that Obj into an array:
const arr = Object.values(jsonList)
Then, get the information you need by using .map function:
const names = arr.map(el=> el.Name)
const runs = arr.map(el=> el.Runs)
In REACT JS, I have a JSON object in state component "myrecords" where items are grouped by their Company Names and it has following format:
{
"Master Automotives": [
{
"SparePartID": "43",
"Name": "Oil and Lubricants",
"Price": "4500",
"VendorID": "48",
"CompanyName": "Master Automotives",
"Qty": 1,
"TotalPrice": "4500"
},
{
"SparePartID": "45",
"Name": "Lights",
"Price": "2300",
"VendorID": "48",
"CompanyName": "Master Automotives",
"Qty": 1,
"TotalPrice": "2300"
}
],
"Repair Solutions": [
{
"SparePartID": "47",
"Name": "Steering Wheel",
"Price": "1500",
"VendorID": "60",
"CompanyName": "Repair Solutions",
"Qty": 1,
"TotalPrice": "1500"
}
],
"FiveStar Automotives": [
{
"SparePartID": "51",
"Name": "Brakes",
"Price": "234",
"VendorID": "70",
"CompanyName": "FiveStar Automotives",
"Qty": 1,
"TotalPrice": "234"
},
{
"SparePartID": "53",
"Name": "Clutch",
"Price": "999",
"VendorID": "70",
"CompanyName": "FiveStar Automotives",
"Qty": 1,
"TotalPrice": "999"
},
{
"SparePartID": "55",
"Name": "LED",
"Price": "288",
"VendorID": "70",
"CompanyName": "FiveStar Automotives",
"Qty": 1,
"TotalPrice": "288"
}
]
}
Im using this method to remove a specific item from myrecords state whenever delete button against an item is clicked:
removeCartItem(CompanyName, sid,e)
{
const items = {...this.state.myrecords};
const j = items[CompanyName].findIndex(item => item.SparePartID === sid);
items[CompanyName].splice([j], 1);
this.setState({
myrecords: items
});
}
Im sending CompanyName, SparePartID as sid in parameters of function to perform delete.
It works Perfectly FINE and deletes the item on which I click.
But problem is if a Company has only 1 item and I delete it, then still the myreocords JSON Object contains that Company with an empty array(no items). Instead I wanted it to delete such a Company who has no Items left in it.
SO that myrecords state should have only those Companies Data whose items are present.
Please help me to solve this Problem.
You should to remove node if it have no items:
removeCartItem(CompanyName, sid,e) {
const items = {...this.state.myrecords};
const j = items[CompanyName].findIndex(item => item.SparePartID === sid);
items[CompanyName].splice([j], 1);
// rm company node if it have no items
if (items[CompanyName].length === 0) {
delete items[CompanyName]
}
this.setState({
myrecords: items
});
}
I have a JSON file that looks a little like this:
[{
"name": "Il Brigante",
"rating": "5.0",
"match": "87",
"cuisine": "Italian",
"imageUrl": "/image-0.png"
}, {
"name": "Giardino Doro Ristorante",
"rating": "5.0",
"match": "87",
"cuisine": "Italian",
"imageUrl": "/image-1.png"
}, {
"name": "Cosme",
"rating": "5.0",
"match": "87",
"cuisine": "Mexican",
"imageUrl": "/image-1.png"
}]
I am trying to loop through the array, identify distinct "cuisine"'s and then create a dictionary with the "name"'s as the value and the matches as an array which will be the key.
Here is an example:
{ Italian:
[{"name": "Il Brigante",
"rating": "5.0", etc},
{"name": "Giardino Doro Ristorante",
"rating": "5.0", etc}],
Mexican:
[{"name": "Cosme",
"rating": "5.0", etc}]
}
Would anyone know how to do this? Any help would be immensely appreciated. Thanks so much in advance!!
Cheers,
Theo
You could use Array.prototype.reduce to create your resulting object.
Array.prototype.reduce()
The reduce() method applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.
Here is an example:
var data = [{
"name": "Il Brigante",
"rating": "5.0",
"match": "87",
"cuisine": "Italian",
"imageUrl": "/image-0.png"
}, {
"name": "Giardino Doro Ristorante",
"rating": "5.0",
"match": "87",
"cuisine": "Italian",
"imageUrl": "/image-1.png"
}, {
"name": "Cosme",
"rating": "5.0",
"match": "87",
"cuisine": "Mexican",
"imageUrl": "/image-1.png"
}]
var res = data.reduce(function(a, b) {
if(a[b['cuisine']]) {
a[b['cuisine']].push( {name: b['name'], rating: b['rating']} )
} else {
a[b['cuisine']] = [ {name: b['name'], rating: b['rating']} ]
}
return a
}, {})
console.log(res)
I think you are going for this.
var byCuisine = {};
myJSON.map(function (obj) {
byCuisine[obj.cusine] = byCuisine[obj.cusine] || [];
//can clone it with JSON.parse(JSON.stringify( )) if you want then
// delete newObj.cuisine to get something like your structure above.
byCuisine[obj.cusine].push(obj);
})
You should also consider using `Array.prototype.forEach
const arr = [{
"name": "Il Brigante",
"rating": "5.0",
"match": "87",
"cuisine": "Italian",
"imageUrl": "/image-0.png"
}, {
"name": "Giardino Doro Ristorante",
"rating": "5.0",
"match": "87",
"cuisine": "Italian",
"imageUrl": "/image-1.png"
}, {
"name": "Cosme",
"rating": "5.0",
"match": "87",
"cuisine": "Mexican",
"imageUrl": "/image-1.png"
}];
const finalObj = {};
arr.forEach( obj => {
if ( ! finalObj[obj.cuisine] ) {
let arr = [];
arr.push(obj);
Object.assign(finalObj, {
[obj.cuisine]: arr
})
} else {
finalObj[obj.cuisine].push(obj)
}
});
console.log(finalObj);
This code declares a global const variable finalObj to hold your desired output.
the arr array of object is been looped in other to get all of it's elements which are objects, then we determine if obj.cusisine exists on the finalObj ( which it does not at the first instance a unique obj.cuisine is seen ). An array is created to hold the value of the entire obj value
I'm trying to sort an array of clothes sizes.
I used the Array.prototype.sort() function defininig an array of sizes and then sorting the input array following the order defined by me in the array
this works with standard sizes like S, M and L but doesn't with sizes like 40, 42, 44 etc.
code sorting the array
if (inputArray['code'] == 'size'){
inputArray.sizes.sort(function(a,b) {
var sizes = ["29","30","31","32","33","34","35","36","37","38","39","40","41","42",
"44","46","48","50","52","54","56","58","60",
"NT","N-USE", "2-3","3-4","4-5","5-6","6-7","7-8","8-9","9-10","10-11","10-13","11-13",
"XXXS","XXS","XX/XS","XS","XS/S","S","S/M","M","M/L","L","L/XL","XL","XL/XX","XXL","XXXL"];
var optionValueA = a['label'];
var optionValueB = b['label'];
html += ' index position ' + optionValueA + '=' + sizes.indexOf(optionValueA) + ' ' + optionValueB + '=' + sizes.indexOf(optionValueB);
return sizes.indexOf(optionValueA)+1 - sizes.indexOf(optionValueB)+1
});
}
html += ' SIZES json= ' + JSON.stringify(inputArray.sizes);
here is the output with standard sizes (well sorted)
index position S=41 M=43 index position M=43 XL=47 index position
XL=47 XXL=49 index position XXL=49 L=45 index position XL=47 L=45
index position M=43 L=45 SIZES json=
[{"id":"646","label":"S","products":["28535"]},{"id":"672","label":"M","products":["28536"]},{"id":"651","label":"L","products":["28539"]},{"id":"691","label":"XL","products":["28537"]},{"id":"640","label":"XXL","products":["28538"]}]
and here the output with numeric sizes (not well sorted)
index position 42=13 44=14 index position 42=13 46=15 index position
46=15 48=16 index position 42=13 48=16 index position 46=15 50=17
index position 50=17 54=19 index position 54=19 52=18 index position
50=17 52=18 index position 46=15 52=18 SIZES json=
[{"id":"687","label":"44","products":["23300"]},{"id":"650","label":"42","products":["23299"]},{"id":"649","label":"48","products":["23302"]},{"id":"643","label":"46","products":["23301"]},{"id":"688","label":"52","products":["23305"]},{"id":"669","label":"50","products":["23303"]},{"id":"684","label":"54","products":["23304"]}]
here the original arrays (before sorting) from debug
numeric sizes
ORIGINAL ARRAY=
[{"id":"650","label":"42","products":["23299"]},{"id":"687","label":"44","products":["23300"]},{"id":"643","label":"46","products":["23301"]},{"id":"649","label":"48","products":["23302"]},{"id":"669","label":"50","products":["23303"]},{"id":"684","label":"54","products":["23304"]},{"id":"688","label":"52","products":["23305"]}]
standard sizes
ORIGINAL ARRAY=
[{"id":"646","label":"S","products":["28535"]},{"id":"672","label":"M","products":["28536"]},{"id":"691","label":"XL","products":["28537"]},{"id":"640","label":"XXL","products":["28538"]},{"id":"651","label":"L","products":["28539"]}]
im not very skilled in js so mabe someone can help
thanks in advance
The problem is that your comparison function is inconsistent, in particular the part
return sizes.indexOf(optionValueA)+1 - sizes.indexOf(optionValueB)+1
// ^^ ^^
If the two compared values are 2 or less indices apart and a should be smaller than b, the function returns the wrong result (>0 instead of <=0). This will lead to the unexpected ordering.
I presume you meant
return (sizes.indexOf(optionValueA)+1) - (sizes.indexOf(optionValueB)+1)
but that's unnecessary and can be simplified to
return sizes.indexOf(optionValueA) - sizes.indexOf(optionValueB)
You could use an object for the sort order and a default value if necessary.
The order is build with the item and an incremented index.
function orderSize(a, b) {
return (order[a.label] || 0) - (order[b.label] || 0);
}
var array1 = [{ "id": "640", "label": "XXL", "products": ["28538"] }, { "id": "646", "label": "S", "products": ["28535"] }, { "id": "672", "label": "M", "products": ["28536"] }, { "id": "651", "label": "L", "products": ["28539"] }, { "id": "691", "label": "XL", "products": ["28537"] }],
array2 = [{ "id": "643", "label": "46", "products": ["23301"] }, { "id": "650", "label": "42", "products": ["23299"] }, { "id": "649", "label": "48", "products": ["23302"] }, { "id": "684", "label": "54", "products": ["23304"] }, { "id": "688", "label": "52", "products": ["23305"] }, { "id": "669", "label": "50", "products": ["23303"] }, { "id": "687", "label": "44", "products": ["23300"] }],
sizes = ["29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "44", "46", "48", "50", "52", "54", "56", "58", "60", "NT", "N-USE", "2-3", "3-4", "4-5", "5-6", "6-7", "7-8", "8-9", "9-10", "10-11", "10-13", "11-13", "XXXS", "XXS", "XX/XS", "XS", "XS/S", "S", "S/M", "M", "M/L", "L", "L/XL", "XL", "XL/XX", "XXL", "XXXL"],
order = {};
sizes.forEach(function (a, i) { order[a] = i + 1; });
array1.sort(orderSize);
array2.sort(orderSize);
console.log(array1);
console.log(array2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you like to sort mixed sizes, you could use directly an object, with mapped sort values for various size systems, like
{
64: 1,
xs: 2,
68: 3,
72: 4
s: 5
76: 6
/* ... */
}