Format JSON from two flat structured array in Javascript - javascript

I need to make a nested JSON out of two flat structured arrays which are kind of linked together, I am able to get the first level but not able to nest it in javascript.
Below is the problem statement.
I have 2 arrays:
data = ["HSP - FS", "FS-M", "Lo Co", "GO A", "CQM","whatever"];
type = ["Epic","Sub - Epic","Sub - Epic","Epic","Sub - Epic","Story"];
the type array and data array are linked together and with type and description on the same index like
type[0] which is data[0], so it will be "Epic: HSP-FS", but this does not end here, this Epic has child elements also which are Sub - Epics and their description is placed under the same array element, so type[1] which is "Sub-Epic" has its data in data[1] which is "FS-M" and so on till next "Epic" is found in the type array.
So JSON would be like
{0:{
Epic: "HSP - FS",
Sub-Epic:"FS-M",
Sub-Epic:"Lo Co"
},
1:{
Epic: "GO A",
Sub-Epic:"CQM",
Story:"whatever"
}}
Structure of array and JSON is fixed, and even array can have any number of Epics, Sub Epics or story but the order will be maintained as in all the child of Epics will be there until next occurrence of Epic happens.
Issue is I am not able to write loop to get the output..I have till now tried something like iterating and joining these two arrays
Thank you in advance for help.

You can't have repeated named properties in a JSON object, but you can use arrays instead:
var array = [];
for(var i=0; i < data.length; ++i)
{
var t = type[i];
var d = data[i];
if (t == "Epic")
{
array.push({ "Epic": d});
}
else
{
if(typeof(array[array.length-1][t]) == "undefined")
{
array[array.length-1][t] = [];
}
array[array.length-1][t].push(d)
}
}
This is the resulting JSON:
[{
"Epic": "HSP - FS",
"Sub - Epic": ["FS-M","Lo Co"]
},
{
"Epic": "GO A",
"Sub - Epic": ["CQM"],
"Story": ["whatever"]
}]

Related

How to Extract data based on the values in one array after matching the corresponding values from another array in JavaScript?

This is the URL from GeoServer to get feature info
{"type":"FeatureCollection","features":[{"type":"Feature","id":"weather_warning_day_1.fid--418ec0da_178b69d5dfc_-715c","geometry":null,"properties":{"issue_date":"2021-04-09","updated_at":"2021-04-09T09:26:33+05:30","utc_time":0,"state_name":"Odisha","state_id":21,"district_name":"MAYURBHANJ","district_id":232,"api_district_name":"MAYURBHANJ","day_1":"6,9,10","day1_color":3}}],"totalFeatures":"unknown","numberReturned":1,"timeStamp":"2021-04-09T15:38:19.536Z","crs":null}
the data I want to extract is of variable: "day_1":"6,9,10"
which I got from the layer and stored it in the variable as
var warning_day_1 = weather_warning_layer_data.features[0].properties.day_1
so basically the input is "day_1":"6,9,10"
which I have stored in the array as
[{"warning":"6"},{"warning":"9"},{"warning":"10"}]
and corresponding output should be Dust Storm, Heat Wave, Hot Day
Dust Storm, Heat Wave, Hot Day
or if the input was "day_1":"2,5"
then output should have been Heavy Rain, Hailstorm
or if the input was "day_1":"1"
then output should have been No Warning
After reading the data of the string and creating its array, I have to compare it with another array and extract the key values (display) corresponding to the key values (warning) in the 1st array.
var warning_data_split = warning_day_1.split(/[ ,]+/);
var warning_data_from_api_array = new Array;
warning_data_from_api_array.push(warning_data_split);
for (var i = 0; i < warning_data_from_api_array.length; i++) {
var item_in_array_to_compare = warning_data_from_api_array[i];
if(warning_data_from_api_array[item_in_array_to_compare.warning_data_from_api_array])
{warning_data_from_api_array[item_in_array_to_compare.warning_data_from_api_array].push(item_in_array_to_compare);}
else {
warning_data_from_api_array[item_in_array_to_compare.warning_data_from_api_array] = [item_in_array_to_compare];}}
let final_array_to_compare = item_in_array_to_compare
final_array_to_compare = final_array_to_compare.map(x => ({warning: x}));
/// this is the first array ////////////
The values in this array are not static in length, as it keeps on changing like, sometimes the array has value [1] or [1,2], [2,5,8], [4,7,12], etc
so I have to extract the corresponding values of display from the lookup array given below
var warning_code_meaning_list = [
{ warning:"1", display:"No Warning"},
{ warning:"2", display:"Heavy Rain"},
{ warning:"3", display:"Heavy Snow"},
{ warning:"4", display:"Thunderstorm & Lightning, Squall etc"},
{ warning:"5", display:"Hailstorm"},
{ warning:"6", display:"Dust Storm"},
{ warning:"7", display:"Dust Raising Winds"},
{ warning:"8", display:"Strong Surface Winds"},
{ warning:"9", display:"Heat Wave"},
{ warning:"10", display:"Hot Day"},
{ warning:"11", display:"Warm Night"},
{ warning:"12", display:"Cold Wave"},
{ warning:"13", display:"Cold Day"},
{ warning:"14", display:"Ground Frost"},
{ warning:"15", display:"Fog"}
]
The data which I am getting in warning_day_1 (in the very first line of the code) is a string (this couldn’t be saved as float/integer in the database column because sometimes there are more than 1 warning for a specific place, so I have stored this as a text in the database)
Which I’m converting to an array after reading it from the API
Now this string, which I am fetching from API has variable data,
Some time single digit like: 1
Sometime multiple : 1,2,3
And each of the integer present in this array corresponds to the specific text shown in the next array like if the warning is 2 it means the heavy rainfall,
but if the string (later converted to an array, with “warning” as a key) has 2,5 as value, it means: heavy rainfall & Hailstorm
I want that the values which come up in array 1 (the dynamic one) got match with the 2nd array ( a sort of lookup array) and fetch its display value as output.
How to do so?
You could use an object to map your warnings to messages.
Try this:
const data = {"type":"FeatureCollection","features":[{"type":"Feature","id":"weather_warning_day_1.fid--418ec0da_178b69d5dfc_-715c","geometry":null,"properties":{"issue_date":"2021-04-09","updated_at":"2021-04-09T09:26:33+05:30","utc_time":0,"state_name":"Odisha","state_id":21,"district_name":"MAYURBHANJ","district_id":232,"api_district_name":"MAYURBHANJ","day_1":"6,9,10","day1_color":3}}],"totalFeatures":"unknown","numberReturned":1,"timeStamp":"2021-04-09T15:38:19.536Z","crs":null}
var warning_code_meaning_list = {
"1":"No Warning",
"2":"Heavy Rain",
"3":"Heavy Snow",
"4":"Thunderstorm & Lightning, Squall etc",
"5":"Hailstorm",
"6":"Dust Storm",
"7":"Dust Raising Winds",
"8":"Strong Surface Winds",
"9":"Heat Wave",
"10":"Hot Day",
"11":"Warm Night",
"12":"Cold Wave",
"13":"Cold Day",
"14":"Ground Frost",
"15":"Fog",
};
results = data["features"].map(feature => {
return feature.properties.day_1.split(',').map(code => {
return warning_code_meaning_list[code];
});
});
That gives you an array of arrays of the displays:
[ [ 'Dust Storm', 'Heat Wave', 'Hot Day' ] ]

Making a Search Filter with JQuery?

So I have a Table made from some json data...
{
"AKH":{
"name": "Amonkhet",
"code": "AKH"
"cards": [
{
"artist": "Izzy",
"cmc": 3,
"colorIdentity": [
"W"
],
"colors": [
"White"
],
"id": "df3a6e0336684c901358f3ff53ec82ff5d7cdb9d",
"imageName": "gideon of the trials",
"layout": "normal",
"loyalty": 3,
"manaCost": "{1}{W}{W}",
"multiverseid": 426716,
"name": "Gideon of the Trials",
"number": "14",
"rarity": "Mythic Rare",
"subtypes": [
"Gideon"
],
"text": "+1: Until your next turn, prevent all damage target permanent would deal.\n0: Until end of turn, Gideon of the Trials becomes a 4/4 Human Soldier creature with indestructible that's still a planeswalker. Prevent all damage that would be dealt to him this turn.\n0: You get an emblem with \"As long as you control a Gideon planeswalker, you can't lose the game and your opponents can't win the game.\"",
"type": "Planeswalker — Gideon",
"types": [
"Planeswalker"
]
},
The Table row ends up looking like this for each of the cards. at the moment I only Attach the ID, Card name, and Mana Cost to each row
<td><a href="#" onclick="showInfo(this.id)"
id="df3a6e0336684c901358f3ff53ec82ff5d7cdb9d">Gideon of the Trials</a></td>
Now I want to search through these cards. (Keep in mind there are over 17,000 different cards that will be on this list) I can get it to find the things.. But I'm having several different issues... Either it finds them all but doesn't hide the rest of the list, or it hides the whole list and only displays one of the found cards.
So question A... What am I missing to make the search work correctly?
$(document).on('change', 'input[type=checkbox]', function() {
var lis = $('.cardsRow')
$('input[type=checkbox]').filter(':checked').each(function(){
filterKeyB = $(this).attr('id')
filterKeyA = $(this).attr('name')
$.each(json, function(setCode, setListing) {
$.each(setListing.cards,function(cardNum, cardListing){
var x = Object.keys(cardListing)
var y = Object.keys(cardListing).map(function (key){
return cardListing[key]
})
for (i = 0; (i < x.length); i++) {
if(x[i] === filterKeyA){
if (y[i] instanceof Array){
var holder = y[i]
var valueArr =[]
for(var k = 0; k < holder.length; k++){
valueArr = holder.join('|').toLowerCase().split('|')
var foundIt = valueArr.includes(filterKeyB)
}
}else{
var stringy = y[i]
var stringyA= stringy.toLowerCase().replace(/\s/g, '')
if (stringyA === filterKeyB){
var foundIt = true
}
}
if(foundIt === true){
$winner = cardListing.name
for (k = 0; (k < lis.length); k++){
if (lis[k].innerText.indexOf($winner) != -1) {
$(lis[k]).show()
}
}
}
}
}
})
Question B... Since you are already here... Would it be better practice to attach the data that can be searched to the element itself? Maybe just the most searched (Like Name and Mana) and have more advanced queries go through the data again?
I don't understand why the code isn't working or even how it works, it looks like it references some functions that aren't defined in the sample. But I can share with you a really simple/intuitive way to filter stuff, I hope you find it useful.
Native filter method is so useful for what you're trying to do, it takes a callback that takes current element as an arg and returns true or false, if true, the element is included in the new array it produces.
But filter only takes one function, and you have many filters, so let's make a function that combines many filter Fns together into one fn, so you can pass them in all at once:
const combineFilters = (...fns) => val => fns.reduce((prev, curr) => prev || curr(val), false);
OK, how about storing the names of the filter functions as keys in an object so we can reference them using a string? That way we could give each checkbox an ID corresponding to the name of the filter function they are supposed to apply, and makes things really easy to implement (and read):
const filterFns = {
startsWithG(card) {
return card.name[0] === 'G';
},
//etc.
};
OK, time to get the IDs of all the checkboxes that are clicked, then map them into an array of functions.
const filters = $('input[type=checkbox]')
.filter(':checked')
.map((e, i) => $(i).attr('id'))
.get()
.map(fnName => filterFns[fnName])
(Assume the relevant data is stored in a var called...data.) We can use combineFilters combined with filters (array of Fns) to activate all of the relevant filters, then map the resulting array of matching objects into the HTML of your choosing.
const matches = data.cards
.filter(combineFilters(...filters))
.map(card => `<div>${card.name}</div>` );
Then time to update DOM with your matches!
As others have noted, if you need to do any more complicated filtering on objects or arrays, lodash library is your friend!

JavaScript - Find objects by similar property and push it in a new array

I have the following JSON tree:
[
{
"category":"PASTAS",
"createdAt":"2016-01-01T19:47:57.813Z",
"currency":"$",
"dishName":"Spaghetti",
"estTime":"10-20 min",
"price":10,
"subName":"Pasta",
"updatedAt":"2016-04-28T20:48:06.800Z"
},
{
"category":"PIZZAS",
"createdAt":"2016-04-19T21:44:56.285Z",
"currency":"$",
"dishName":"Ai Funghi Pizza ",
"estTime":"20-30 min",
"price":20,
"subName":"Pizza",
"updatedAt":"2016-04-28T20:58:39.499Z"
},
{
"category":"PIZZAS",
"createdAt":"2016-04-19T21:44:56.285Z",
"currency":"$",
"dishName":"Seafood Pizza",
"estTime":"20-30 min",
"price":10,
"subName":"Pizza",
"updatedAt":"2016-04-28T20:58:39.499Z"
}
]
As you can see in the JSON tree the element category:"PIZZAS" repeats two times, what I would like to do is to either create a new array or organize these results in a way to avoid repetition in all the other duplicates, i.e. in the example above, I would have a final results like this:
Pastas:
Spaghetti
Pizza:
Ai Fungi Pizza,
Seafood Pizza
Any ideas on how to achieve the wanted result?
Assuming the array is named data, this should do the trick:
var result = {}; // Create an output object.
for(var i = 0; i < data.length; i++){ // Loop over the input array.
var row = data[i]; // Store the current row for convenience.
result[row.category] = result[row.category] || []; // Make sure the current category exists on the output.
result[row.category].push(row.dishName); // Add the current dish to the output.
}
lodash#groupBy is exactly what you want.
lodash.groupBy(foods, function(food) { return food.category; });
Here's an example with your JSON:
http://codepen.io/damongant/pen/xVQBXG

Looping through nesting of objects and arrays with Javascript and underscore

I am trying to access objects that are nested within an array. I start with this JSON object (which was derived from an XML database output):
{"report":
{"date":"15 Apr 2016",
"metrics":
{"metric":
[
{"name":"Bank Angle",
"display_parent_group":"Bankfull",
"display_child_group":"SiteShape",
"tolerance":"0.05",
"visits":
{"visit":
[
{"visit_id":"3047","value": "0.47"},
{"visit_id":"2164","value": "0.55"},
{"visit_id":"1568","value": "0.72"},
{"visit_id":"3431","value": "0.12"},
{"visit_id":"2428","value": "0.44"},
{"visit_id":"1567","value": "0.49"}
]}},
{"name":"Bank Angle SD",
"display_parent_group":"Bankfull",
"display_child_group":"SiteShape",
"tolerance":"0.05",
"visits":
{"visit":
[
{"visit_id":"3047","value": "0.12"},
{"visit_id":"2164","value": "0.05"},
{"visit_id":"1568","value": "0.21"},
{"visit_id":"3431","value": "0.68"},
{"visit_id":"2428","value": "0.22"},
{"visit_id":"1567","value": "0.13"}
]}},
{"name":"Bankfull Area",
"display_parent_group":"Bankfull",
"display_child_group":"SiteSize","tolerance":"0.05",
"visits":
{"visit":
[
{"visit_id":"3047","value": "202"},
{"visit_id":"2164","value": "193"},
{"visit_id":"1568","value": "115"},
{"visit_id":"3431","value": "258"},
{"visit_id":"2428","value": "89"},
{"visit_id":"1567","value": "206"}
]}}
]
}
}
}
I then use underscore to extract a subset of metric objects:
var table_metric = JSONData.report.metrics.metric;
var target_metrics = _.where(table_metric, {
display_parent_group : 'Bankfull', display_child_group: 'SiteShape'
});
This results in an array with two nested objects. Where I'm having a problem is then accessing the array of objects which is nested inside visits.visit. If, for instance, I want to build an array of values associated with the key visit_id, and I try:
function buildVisitIDArray(target_metrics) {
var attrList = [];
for(var i=0; i<target_metrics.length; i++) {
var visit_records = target_metrics[i].visits[1];
console.log(visit_records);
for(visit_record in visit_records) {
attrList.push(_.pluck(visit_record, "visit_id"));
}
}
return attrList
}
I just get an array of undefined results. I've spent hours trying variations on the syntax to get at the nested "visit" objects, but I just can't seem to figure it out.
Any help is much appreciated for this novice!
In your buildVisitIDArray function, you are trying to get target_metrics[i].visits[1] as if it was an array, but it's actually an object, so you should use it this way:
function buildVisitIDArray(target_metrics) {
attrList = [];
for(var i=0; i<target_metrics.length; i++) {
var visit_records = target_metrics[i].visits; // Removed the array call ([1])
console.log(visit_records);
for(visit_record in visit_records) {
attrList.push(_.pluck(visit_records[visit_record], "visit_id"));
}
}
return attrList;
}
Hope it helps :)
You may also have an issue if you're not defining attrList with the var keyword somewhere else in your code.
Building on Andre's answer, you may want to change this line to be:
visit_records = target_metrics[i].visits.visit;
to go one layer deeper, then do a regular array for loop afterward.

How do i reverse JSON in JavaScript?

[
{"task":"test","created":"/Date(1291676980607)/"},
{"task":"One More Big Test","created":"/Date(1291677246057)/"},
{"task":"New Task","created":"/Date(1291747764564)/"}
]
I looked on here, and someone had the same sort of question, but the "checked" correct answer was that it will be different on IE if the item is deleted, which would be fine. My issue is, those items above are stored, but when i go and grab them, iterate, and return, the items are reversed and the created is at the 0 index and task is at 1. Also, i need to return this as JSON.
Here is my basic JS (value == an int the user is passing in):
outputJSON = {};
for(x in json[value]){
outputJSON[x] = _objectRevival(json[value][x]);
}
return outputJSON;
That returns:
created: Mon Dec 06 2010 15:09:40 GMT-0800 (Pacific Standard Time)
task: "test"
The order of the properties of an object is undefined. It is not possible to force them in a specified order. If you need them in a specific order, you can build this structure reliably using arrays:
var values = [
[["task", "test"], ["created", "/Date(1291676980607)/"]],
[["task", "One More Big Test"], ["created", "/Date(1291677246057)/"]],
[["task", "New Task"], ["created", "/Date(1291747764564)/"]]
];
Then you can iterate over your structure like this:
for (var i = 0; i < values.length; i++) {
for (var k = 0; k < values[i]; k++) {
// values[i][k][0] contains the label (index 0)
// values[i][k][1] contains the value (index 1)
}
}
To enforce a particular order for your output just replace json[value] in your for loop with an array of the object properties in the order you want to display them, in your case ["task", "created"].
The problem is that javascript objects don't store their properties in a specific order. Arrays on the other do (hence why you can get something consistent from json[0], json[1], json[2]).
If your objects will always have "task" and "created", then you can get at them in any order you want.
json[value]["task"]
and
json[value]["created"]
Update:
This should work with your existing code.
Before sending the json object:
var before = [
{"task":"test","created":"/Date(1291676980607)/"},
{"task":"One More Big Test","created":"/Date(1291677246057)/"},
{"task":"New Task","created":"/Date(1291747764564)/"}
];
var order = [];
for (var name in before[0]) {
order.push(name); // puts "task", then "created" into order (for this example)
}
Then send your json off to the server. Later when you get the data back from the server:
var outputJSON = {};
for (var x in order) {
if (order.hasOwnProperty(x)) {
outputJSON[order[x]] = _objectRevival(json[value][order[x]]); // I'm not sure what _objectRevival is...do you need it?
}
}
return outputJSON;
var items = ["bag", "book", "pen", "car"];
items.reverse();
This will result in the following output:
car , pen, book, bag
Even if you have JSON array it will reverse.

Categories

Resources