Get unique values from array of dictionaries and create a new dictionary - javascript

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

Related

How to send json result as a Dictionary instead of Array in expressjs

I want to send response as a dictionary like this:
{
"id": 5928101,
"category": "animal welfare",
"organizer": "Adam",
"title": "Cat Cabaret",
"description": "Yay felines!",
"location": "Meow Town",
"date": "2019-01-03T21:54:00.000Z",
"time": "2:00",
}
But I am using bellow code, which results an array
var ress = JSON.stringify(sqlResults)
console.log('response json:' + ress)
res.send(ress)
The resulted array has brackets [] like this:
[
{
"id": 5928101,
"category": "animal welfare",
"organizer": "Adam",
"title": "Cat Cabaret",
"description": "Yay felines!",
"location": "Meow Town",
"date": "2019-01-03T21:54:00.000Z",
"time": "2:00",
}
]
How can I send result without a third bracket?
If you return the first element of your sqlResults array you should get the result you wish.
You should also be able to use res.json(dict) to send your result to the client.
sqlResults = [
{
"id": 5928101,
"category": "animal welfare",
"organizer": "Adam",
"title": "Cat Cabaret",
"description": "Yay felines!",
"location": "Meow Town",
"date": "2019-01-03T21:54:00.000Z",
"time": "2:00",
}
];
const dict = sqlResults[0];
var ress = JSON.stringify(dict, null, 2)
console.log('response json:' + ress)
// You can then send using res.send(ress);
// Or simply res.json(dict);

Count the number of occurrences of each item in an array and regex

I am trying to get the result of the below array though no idea what am I missing here,
[
{
"Id": "10",
"FileName": "TechnicalBook_2021-08-26T12:36:48Z",
"Book": "ABC P1",
"Location": "USA",
"LastModified": "2021-08-26T12:36:48Z"
},
{
"Id": "11",
"FileName": "SocialBook_2021-08-26T12:36:48Z",
"Book": "XYZ P1",
"Location": "USA",
"LastModified": "2021-08-26T15:36:48Z"
},
{
"Id": "12",
"FileName": "TechnicalBook_2021-08-26T15:36:48Z",
"Book": "ABC P2",
"Location": "USA",
"LastModified": "2021-08-26T12:36:48Z"
},
{
"Id": "13",
"FileName": "SocialBook_2021-08-26T15:36:48Z",
"Book": "XYZ P2",
"Location": "USA",
"LastModified": "2021-08-26T15:36:48Z"
},
{
"Id": "14",
"FileName": "SocialBook_2021-08-26T17:36:48Z",
"Book": "XYZ P3",
"Location": "USA",
"LastModified": "2021-08-26T17:36:48Z"
}
]
And I am trying to obtain below output
[
{
"FileName": "TechnicalBook",
"TechnicalBook_Count": "2"
},
{
"FileName": "SocialBook",
"SocialBook_Count": "3"
}
]
Below code, I tried though not getting the proper output, any alternate suggestions here? Because 'FileName' will change every time, new DateTime will append in FileName.
var occurrences = { };
for (var i = 0, j = arr.length; i < j; i++) {
occurrences[arr[i]] = (occurrences[arr[i]] || 0) + 1;
}
You can do it like this:
var data =
[
{
"Id": "10",
"FileName": "TechnicalBook_2021-08-26T12:36:48Z",
"Book": "ABC P1",
"Location": "USA",
"LastModified": "2021-08-26T12:36:48Z"
},
{
"Id": "11",
"FileName": "SocialBook_2021-08-26T12:36:48Z",
"Book": "XYZ P1",
"Location": "USA",
"LastModified": "2021-08-26T15:36:48Z"
},
{
"Id": "12",
"FileName": "TechnicalBook_2021-08-26T15:36:48Z",
"Book": "ABC P2",
"Location": "USA",
"LastModified": "2021-08-26T12:36:48Z"
},
{
"Id": "13",
"FileName": "SocialBook_2021-08-26T15:36:48Z",
"Book": "XYZ P2",
"Location": "USA",
"LastModified": "2021-08-26T15:36:48Z"
},
{
"Id": "14",
"FileName": "SocialBook_2021-08-26T17:36:48Z",
"Book": "XYZ P3",
"Location": "USA",
"LastModified": "2021-08-26T17:36:48Z"
}
]
var prefixesAll = data.map(a => a.FileName.split('_')[0]);
var prefixesUnique = [...new Set(prefixesAll)];
var prefixCounts = prefixesUnique.map(a => ({
"FileName": a,
"Count": data.filter(b => b.FileName.startsWith(a)).length
}));
console.log(prefixesAll);
console.log(prefixesUnique);
console.log(prefixCounts);
In an array of objects you should always aim for each object to have the same keys, so I've done that here.
That code will output all of the prefixes, then a unique list of the prefixes, then the count of each prefix:
[
"TechnicalBook",
"SocialBook",
"TechnicalBook",
"SocialBook",
"SocialBook"
]
[
"TechnicalBook",
"SocialBook"
]
[
{
"FileName": "TechnicalBook",
"Count": 2
},
{
"FileName": "SocialBook",
"Count": 3
}
]
What you're doing here is not so much counting occurrences but transforming data from one format into another. However, you only need to take a couple of steps to convert your data into another format. See comments below...
// your data
var dataArr = [
{
"Id": "10",
"FileName": "TechnicalBook_2021-08-26T12:36:48Z",
"Book": "ABC P1",
"Location": "USA",
"LastModified": "2021-08-26T12:36:48Z"
},
{
"Id": "11",
"FileName": "SocialBook_2021-08-26T12:36:48Z",
"Book": "XYZ P1",
"Location": "USA",
"LastModified": "2021-08-26T15:36:48Z"
},
{
"Id": "12",
"FileName": "TechnicalBook_2021-08-26T15:36:48Z",
"Book": "ABC P2",
"Location": "USA",
"LastModified": "2021-08-26T12:36:48Z"
},
{
"Id": "13",
"FileName": "SocialBook_2021-08-26T15:36:48Z",
"Book": "XYZ P2",
"Location": "USA",
"LastModified": "2021-08-26T15:36:48Z"
},
{
"Id": "14",
"FileName": "SocialBook_2021-08-26T17:36:48Z",
"Book": "XYZ P3",
"Location": "USA",
"LastModified": "2021-08-26T17:36:48Z"
}
];
// create storage object
var fileObject = {};
// loop through data
dataArr.forEach(d => {
// get the fileName (remove date)
let fileName = d.FileName.split("_")[0];
// check if fileObject has a fileName property
// if not add it and set it to 0
fileObject[fileName] = fileObject[fileName] || 0,
// then/else increment the count
fileObject[fileName] += 1
}),
This will give you:
console.log("fileObject:", fileObject)
//=> fileObject: { TechnicalBook: 2, SocialBook: 3 }
Now that you've done the counting then it's simply a matter of reformatting:
// create output array
var bookArr = [];
// loop through fileObject
Object.keys(fileObject).forEach(key => {
// create a temporary object
let obj = {
FileName: key
};
// add the count to obj
obj[`${key}_Count`] = fileObject[key],
// add obj to the array
bookArr.push(obj)
})
This will give you:
console.log("bookArr:", bookArr)
/*=> bookArr: [ { FileName: 'TechnicalBook', TechnicalBook_Count: 2 },
{ FileName: 'SocialBook', SocialBook_Count: 3 } ]
*/
And as you seem to want the output in JSON format then:
var bookJSON = JSON.stringify(bookArr, null, 4);
console.log(bookJSON)
/*
[
{
"FileName": "TechnicalBook",
"TechnicalBook_Count": 2
},
{
"FileName": "SocialBook",
"SocialBook_Count": 3
}
]
*/
Hoped that helped. :)

Vue.js Computed Property Filtering

I have a Vue.js computed property as follows.
odds() {
let race = this.data.events.runners.filter(item => item.course === this.course && item.time === this.time)
let runner = race[0].data.filter(item => item.name === this.runner)
return runner[0].odds
}
Although it returns the expected value I think it looks dirty. Can any one suggest best way to write this code.
Sample JSON is as follows.
{
"courses": [{
"type": "horses",
"course": "Exeter"
}],
"runners": [{
"course": "Exeter",
"time": "14:10",
"data": [{
"number": "1",
"name": "White Lilac",
"odds": "6\/1"
}, {
"number": "2",
"name": "Sauvignon",
"odds": "5\/1"
}, {
"number": "3",
"name": "Foxy Lass",
"odds": "33\/1"
}, {
"number": "4",
"name": "Hot Ryan",
"odds": "8\/1"
}, {
"number": "5",
"name": "Arqalina",
"odds": "11\/8"
}, {
"number": "6",
"name": "Presenting Lucina",
"odds": "14\/1"
}, {
"number": "7",
"name": "Persistantprincess",
"odds": "12\/1"
}, {
"number": "8",
"name": "Windy Bottom",
"odds": "20\/1"
}, {
"number": "9",
"name": "Shotgun Sally",
"odds": "33\/1"
}, {
"number": "10",
"name": "Rule The Ocean",
"odds": "9\/1"
}, {
"number": "11",
"name": "Avithos",
"odds": "12\/1"
}, {
"number": "12",
"name": "Monet Moor",
"odds": "16\/1"
}]
}]
}
I would like to know if there is a much better way to do this. Thanks in advance.
Your existing code is nice enough. but one change is your course and time make it unique fields so there will only be one index always so its better to exit early. (you can add false check for not found yourself).
var requiredCourse = (courseDetails)=>courseDetails.course === this.selectedCourse && courseDetails.time === this.selectedTime;
var requiredhorse = (horse)=> horse.name === this.runner;
var courseIndex = data.findIndex(requiredCourse);
var horseOdds = data[courseIndex].data.findIndex(requiredhorse);
console.log(data[courseIndex].data[horseOdds])
But if you have the ability to change the JSON structure. then just directly make the course and time as keys so you can directly access without need for filter or findIndex. hope this make is it little bit cleaner for your liking.

Change JSON format/layout

I have a universal variable on my website which includes line items with relevant details. These line items are reflective of what the user has in their cart. I am integrating with a third party who require the data passed through to them to be formatted slightly different. The below is the data layer currently on my website:
"lineItems": [
{
"product": {
"id": "s83y016b5",
"sku_code": "s83y016b5",
"url": "/en-gb/jeans/p/s83y016b5",
"image_url": "http://www.my-website.com/a/p/shirt.jpeg",
"name": "Jeans",
"manufacturer": "",
"category": "Everyday Wear",
"stock": 116,
"currency": "GBP",
"unit_sale_price": 16,
"unit_price": 16,
"size": "6-9 Months",
"color": "Indigo"
},
"quantity": 1
}
]
The below is what format the third party needs:
"lineItems": [
{
"sku": "s83y016b5",
"name": "Jeans",
"description": "A super great pair of jeans.",
"category": "Everyday Wear",
"other": {"fieldName": "This can be a string or any value you like"}
"unitPrice": 11.99,
"salePrice": 11.99,
"quantity": 2,
"totalPrice": 23.98
"imageUrl": "http://www.my-website.com/a/p/shirt.jpeg",
"productUrl": "http://www.my-website.com/index.php/shirt.html",
}]
Obviously this needs to be dynamic based on the products in the cart. What I intend to do is use javascript to amend the data and send this to the third party via Google Tag Manager.
Any help would be greatly appreciated. Any questions welcome.
This should be close to what you're looking for.
let oldLineItems = "your object";
let newLineItems = {};
newLineItems.lineItems = [];
for (let i in oldLineItems.lineItems) {
newLineItems.lineItems[i] = {};
for (let key in oldLineItems.lineItems[i].product)
{
newLineItems.lineItems[i][key] = oldLineItems.lineItems[i].product[key];
}
}
See code below.
I'm not sure how your lineItems object is set up, but below I just created an array called line Items. If line items is a key in an object which I suspect from your snippet above, you will have to go a level deeper in the for loops used in my example below.
Simply add further details to the new object in the nested for in loops below.
var lineItems =
[
{
"product": {
"id": "s83y016b5",
"sku_code": "s83y016b5",
"url": "/en-gb/jeans/p/s83y016b5",
"image_url": "http://www.my-website.com/a/p/shirt.jpeg",
"name": "Jeans",
"manufacturer": "",
"category": "Everyday Wear",
"stock": 116,
"currency": "GBP",
"unit_sale_price": 16,
"unit_price": 16,
"size": "6-9 Months",
"color": "Indigo",
"description": 'Some random description'
},
"quantity": 1
},
{
"product": {
"id": "s83y01699",
"sku_code": "s83y01699",
"url": "/en-gb/pants/p/s83y016b5",
"image_url": "http://www.my-website.com/a/p/pants.jpeg",
"name": "Pants",
"manufacturer": "",
"category": "Casual Wear",
"stock": 90,
"currency": "au",
"unit_sale_price": 14,
"unit_price": 14,
"size": "6-9 Months",
"color": "Indigo",
"description": 'Some random description'
},
"quantity": 14
},
];
var newLineItems = [];
for(var char in lineItems){
// Adding some values to newLineItems.
newLineItems.push({
sku: lineItems[char].product.sku_code,
name: lineItems[char].product.name,
description: lineItems[char].product.description,
category: lineItems[char].product.category,
quantity: lineItems[char].quantity
});
}
console.log(JSON.stringify(newLineItems));

Using underscore.js to find values in deeply nested JSON

I'm pretty new to Javascript, and I just learned about underscore.js. I have a deeply nested JSON object, and I need to use underscore to find key/value pairs, which I will then use to populate various HTML tables. If the structure was more shallow, using something like _.pluck would be easy, but I just don't know how to traverse past the first couple of nesting levels (i.e. surveyGDB, table, tablenames). The JSON object comes from an XML that is comprised of multiple nesting structures (mashed up from different database tables).
var JSONData =
"surveyGDB": {
"filename": "..\\Topo\\SurveyGeoDatabase.gdb",
"table": {
"tablename": [
{
"#text": "SurveyInfo\n ",
"record": {
"OBJECTID": "1",
"SiteID": "CBW05583-345970",
"Watershed": "John Day",
"VisitType": "Initial visit",
"SurveyInstrument": "Total Station",
"ImportDate": "2015-07-22T09:08:42",
"StreamName": "Duncan Creek",
"InstrumentModel": "TopCon Magnet v2.5.1",
"FieldSeason": "2015"
}
},
{
"#text": "QaQcPoints\n ",
"record": [
{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tp",
"Count": "357"
},
{
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tb",
"Count": "92"
},
{
"OBJECTID": "3",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "to",
"Count": "8"
},
{
"OBJECTID": "4",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bl",
"Count": "279"
},
{
"OBJECTID": "5",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bf",
"Count": "18"
}
]
},
{
"#text": "QaQcPolygons\n ",
"record": [
{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:43:08",
"SurveyExtentCount": "",
"WaterExtentCount": "",
"ChannelUnitsCount": "",
"ChannelUnitsUnique": ""
},
{
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T13:35:15",
"SurveyExtentCount": "1",
"WaterExtentCount": "1",
"ChannelUnitsCount": "21",
"ChannelUnitsUnique": "21"
}
]
}
]
}
}
}
For instance, I wanted all of the values for 'Code' in the 'QaQCPoints' table, so I tried:
var codes = _.flatten(_.pluck(JSONData.surveyGDB.table.tablename[1].record[0], "Code" ));
console.log(codes);
In the console, this returns an array with a length of 5, but with blank values.
What am I doing wrong?
I'd also rather search for the 'Code' values in the table based on something like the '#text' key value, instead of just using it's position in the object.
If I understood you correctly, you want to always search the record array within JSONData.surveyGDB.table.tablename array for some queries. This means you need to find the record based on some parameter and return something from the found record.
Do note that the record property is sometimes an array and sometimes an object (for table SurveyInfo) in your example so I'll assume you need to take this into account.
You can make a small function to extract data and handle both objects and arrays:
function extract(record, prop) {
if (Array.isArray(record)) {
return _.pluck(record, prop);
} else {
return record[prop];
}
}
Usage example:
I wanted all of the values for 'Code' in the 'QaQCPoints' table.
I'd also rather search for the 'Code' values in the table based on something like the '#text' key value, instead of just using it's position in the object.
To achieve this you first find a record using _.find, and then extract Code values from it using the method above:
var table = JSONData.surveyGDB.table.tablename;
// find an item that has `#text` property equal to `QaQcPoints`
var item = _.find(table, function(r) {
return r['#text'] === 'QaQcPoints';
});
// extract codes from the found item's record property
var code = extract(item.record, 'Code');
// output ["tp", "tb", "to", "bl", "bf"]
Running sample:
var JSONData = {
"surveyGDB": {
"filename": "..\\Topo\\SurveyGeoDatabase.gdb",
"table": {
"tablename": [{
"#text": "SurveyInfo",
"record": {
"OBJECTID": "1",
"SiteID": "CBW05583-345970",
"Watershed": "John Day",
"VisitType": "Initial visit",
"SurveyInstrument": "Total Station",
"ImportDate": "2015-07-22T09:08:42",
"StreamName": "Duncan Creek",
"InstrumentModel": "TopCon Magnet v2.5.1",
"FieldSeason": "2015"
}
}, {
"#text": "QaQcPoints",
"record": [{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tp",
"Count": "357"
}, {
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "tb",
"Count": "92"
}, {
"OBJECTID": "3",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "to",
"Count": "8"
}, {
"OBJECTID": "4",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bl",
"Count": "279"
}, {
"OBJECTID": "5",
"TIMESTAMP": "2015-07-22T09:18:43",
"Code": "bf",
"Count": "18"
}]
}, {
"#text": "QaQcPolygons",
"record": [{
"OBJECTID": "1",
"TIMESTAMP": "2015-07-22T09:43:08",
"SurveyExtentCount": "",
"WaterExtentCount": "",
"ChannelUnitsCount": "",
"ChannelUnitsUnique": ""
}, {
"OBJECTID": "2",
"TIMESTAMP": "2015-07-22T13:35:15",
"SurveyExtentCount": "1",
"WaterExtentCount": "1",
"ChannelUnitsCount": "21",
"ChannelUnitsUnique": "21"
}]
}]
}
}
}
function extract(record, prop) {
if (Array.isArray(record)) {
return _.pluck(record, prop);
} else {
return record[prop];
}
}
var table = JSONData.surveyGDB.table.tablename;
var item = _.find(table, function(r) {
return r['#text'] === 'QaQcPoints';
});
console.dir(item);
var code = extract(item.record, 'Code');
console.log(code);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
You have a two stage problem. Stage one is figuring out which table is QaQcPoints. If that's always JSONData.surveyGDB.table.tablename[1], you're good.
The next stage is getting your data out. You can use native array manipulation most of the time (unless you're on really old browsers). So:
var table = JSONData.surveyGDB.table.tablename[1].record;
var codeArray = table.map(function(val) { return val.Code; });
Will do the trick.

Categories

Resources