How to map this array into a new format with JavaScript - javascript

I know there is some functional programming in JavaScript and I am wondering if I can create a function like so using some functional methods easier than just writing the code up myself the procedural way (as you can see below, I am also having some SO formatting issue for some reason).
function mapToFormat(var myarray, var colname) {
}
myarray is actually the following json from a server response...
{
"time": "1",
"col1": "2",
"col2": "3",
"col3": "1"
},
{
"time": "2",
"col2": "3"
},
{
"time": "3",
"col1": "3"
},
{
"time": "4",
"col3": "3"
},
{
   "time": "5",
   "col1": null
}
I would like to call the function on the above json like so
mapToFormat(myarray, 'col1')
and then have it return data like so (in an array format though)
{
"time": "1",
"col1": "2"
},
{
"time": "3",
"col1": "3"
},
{
   "time": "5",
   "col1": "null
}
I am thinking maybe I just use
var newData = [];
$.each(data, function (index, value) {
if(value[colname] not exist) {
newData.push({
"time": value['time'],
colname : value[colname]
}
});
});
but I am not sure how to tell the difference between "col1" not being there and "col1" : null as I want to pass through any null values that come through as well.
How I can achieve this? And I am wondering if there is a map function or something I should be using that might be better?

Try this (fiddle: http://jsfiddle.net/GNr8N/1/):
function mapToFormat(myArray, col) {
return myArray.map(function(record){
var result = {
time: record.time,
}
if (typeof record[col] !== 'undefined') {
result[col] = record[col]
}
return result;
})
}
The !== operator does not do type casting, so if record[col] exists, it will be added, even if it is null.

Related

Filter nested observable array RxJs Angular

I am trying to filter some observable nested array in angular with the filter function in combination pipe function of the RxJs library.
Question:
I only want to show the categories with surveys given by a specific date.
Simplified situation:
My angular component has 3 radiobuttons (values 1,2,3). If i click on one of them it goes to my 'FilterChanged($event.value)' function. In this function i would like to filter the data that is provided by an api. This api at first provides all the categories. After retrieving the data i would like to filter according to the radio-button.
This is the data i get back from the api:
[
{
"category": "A",
"surveys": [
{
"day": "1",
"answers": [
{
"name": "1",
"value": "a"
},
{
"name": "2",
"value": "b"
},
{
"name": "3",
"value": "c"
}
]
},
{
"day": "2",
"answers": [
{
"name": "1",
"value": "a"
},
{
"name": "2",
"value": "b"
},
{
"name": "3",
"value": "c"
}
]
},
{
"day": "3",
"answers": [
{
"name": "1",
"value": "a"
},
{
"name": "2",
"value": "b"
},
{
"name": "3",
"value": "c"
}
]
}
]
},
{
"category": "B",
"surveys": [
{
"day": "2",
"answers": [
{
"name": "1",
"value": "a"
},
{
"name": "2",
"value": "b"
},
{
"name": "3",
"value": "c"
}
]
},
{
"answers": [
{
"name": "1",
"value": "a"
},
{
"name": "2",
"value": "b"
},
{
"name": "3",
"value": "c"
}
]
},
{
"day": "2",
"answers": [
{
"name": "1",
"value": "a"
},
{
"name": "2",
"value": "b"
},
{
"name": "3",
"value": "c"
}
]
}
]
}
]
If radio button 1 is selected i would like to only show the category A and only show it has 1 survey because thats the only survey matching the filter.
Whyd doesn't this code works?? the update filter gets triggerd at the radiobox change event. For me this is much more readable than the reduce with spreader functions.
updateFilter(filterDays : number): void {
var filterDate = this.getFilterDate(filterDays);
this.surveyTypes$ = this.allSurveyTypes$.pipe(map((types) => this.filterSurveyTypes(types, filterDate)));
}
filterSurveyTypes(types : SurveyType[], filterDate : Date) : SurveyType[] {
return types.filter(type => type.surveys.filter(survey => moment(survey.filledInDate).isSameOrAfter(filterDate)).length);
}
and a lot more variations but it does not seem to work.
I think i should not need a map because i am not transforming any data so filter should be fine but is not working for me so far.
I appreciate any help. Thanks
not positive what you're looking for, but it seems like you want to filter the outer array based on what's in the inner array and also filter the inner array, this can be achieved in one pass with reduce:
function filterOuterByInner(array, value) {
return array.reduce((acc, v) => {
const tmp = { ...v }; // create shallow copy
tmp.surveys = tmp.surveys.filter(a => a.day === value); // filter surveys array by value
if (tmp.surveys.length)
acc.push(tmp); // add to acc array if any surveys after filter
return acc;
}, []);
}
then just use it in your map:
this.categories$ = combineLatest(this.allcategories$, this.value$).pipe(map(([categories, val]) => filterOuterByInner(categories, val)));
This would work for you too:
let teste = [];
allcategories.forEach( category => {
category.surveys.forEach( survey => {
if (survey.day == '1'){
teste.push(survey)
}
})
})
It depends how you are using the observable, here are 2 examples :
If you want to set the categories in a property, not as observable, you have to use the subscribe method like this:
this.subscription = this.categories$.subscribe({
next: categories => this.categories = categories
});
then use this.categories. In this case do no not forget to call this subscription.unsubscribe() when destroying the component.
If you are using it in your component template with the async pipe it should work fine.
Remark: an observable is not activated if there is no subscribe (the async pipe does the subscribe and unsubscribe)
The problem I am seeing here is: the filter function is not synchronous. This means, when you call the second filter, the first is answered with a Promise-like response. Since your code is not asynchronous, filter will respond with all the elements, or none.
To solve this problem, you would have to declare your function as an asynchronous function.
Here's some example on how to do so:
async function awesomeFilter(allcategories){
return await allcategories.filter(category =>
category.surveys.filter(survey => survey.day == '1').length
)
}
The survey.day would be your nested verification;
The .length would return to the first filter 0 if no correspondences are found or positive value if there are, telling the first filter where the correspondences are.
This way I was able to make it work. Hopefully it will help you.

Getting JSON object titles

I've tried searching on here, but I can't figure this out.
I'm trying to do an each function that grabs each title of the object, my json is.
{"games":{
"featured": [
{
"game_id": "2"
},
{
"game_id": "15",
}
],
"popular": [
{
"game_id": "2"
}
],
"new": [
{
"game_id": "2",
},
{
"game_id": "15",
},
{
"game_id": "1",
}
]
}}
My JS is:
$.getJSON("apilink",
function(data) {
$.each(data.games, function(i,category){
alert(category[0]);
});
});
I'm obviously trying to rotate through featured, popular and new. What am I doing wrong? Thanks!
You can use nested $.each() calls to iterate each array of objects at category : property name of "games" property of data
var data = {
"games": {
"featured": [{
"game_id": "2"
}, {
"game_id": "15",
}],
"popular": [{
"game_id": "2"
}],
"new": [{
"game_id": "2",
}, {
"game_id": "15",
}, {
"game_id": "1",
}]
}
};
$.each(data.games, function(i, category) {
console.log(i + ":");
$.each(category, function(key, obj) {
console.log(obj)
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js">
</script>
I suppose you want to get featured, popular, new? You already have your answer, The first argument i returns the key of the object, where the second argument returns the value which is category.
$.each(data.games, function(i, category) {
// category is what you are looking for
alert(JSON.stringify(category));
//or
alert(JSON.stringify(data.games[i]));
});
Hope that helps

Angular Firebase retrieving collected data from anonymous users

I have a survey system using Angular and Firebase which stores the results of users answers inside of an object specific to each user. This works well for storing data, but I've realized that it may be difficult to pull the data back out due to each object having a unique name.
I'd like to loop over each object and pull the all of the values together. So for all 50 entries find the total of comprehension.icons.damage[1]
How can I construct a loop that goes over objects with unique names like the objects below?
Here is my json structure
"usersanonymous:-JgTyGt6An3WWyLvnnuu" : {
"comprehension" : {
"-JgTzC0r_H58n7y8Al_-" : {
"date" : 1422154060632,
"icons" : [ {
"damage" : [ null, "0", "3", "3" ],
"ocular" : [ null, "2", "3", "1" ],
"physical therapy" : [ null, "0", "4", "4" ],
"skin" : [ null, "4", "0", "1" ]
} ]
}
}
},
"usersanonymous:-JgU-ryIpI-HR7D4VDkp" : {
"comprehension" : {
"-JgU0MwBwisNbjvRFGOT" : {
"date" : 1422154629142,
"icons" : [ {
"damage" : [ null, "0", "3", "4" ],
"ocular" : [ null, "1", "4", "3" ],
"physical therapy" : [ null, "2", "4", "3" ],
"skin" : [ null, "4", "1", "3" ]
} ]
}
}
}
Given your input data, I would create a function to extract just the data you're interested in. I've written this in raw javascript - if you're using jQuery you may have fun using $.map rather than for (x in y).
var data = {
"usersanonymous:-JgTyGt6An3WWyLvnnuu": {
"comprehension": {
"-JgTzC0r_H58n7y8Al_-": {
"date": 1422154060632,
"icons": [{
"damage": [null, "0", "3", "3"],
"ocular": [null, "2", "3", "1"],
"physical therapy": [null, "0", "4", "4"],
"skin": [null, "4", "0", "1"]
}]
}
}
},
"usersanonymous:-JgU-ryIpI-HR7D4VDkp": {
"comprehension": {
"-JgU0MwBwisNbjvRFGOT": {
"date": 1422154629142,
"icons": [{
"damage": [null, "0", "3", "4"],
"ocular": [null, "1", "4", "3"],
"physical therapy": [null, "2", "4", "3"],
"skin": [null, "4", "1", "3"]
}]
}
}
}
};
function extractComprehension(rawData) {
var result = [];
for (var usersanonymous in rawData) {
usersanonymous = rawData[usersanonymous];
if (usersanonymous.comprehension) {
for (var token in usersanonymous.comprehension) {
token = usersanonymous.comprehension[token];
if (token.icons) {
result.push(token.icons[0]);
}
}
}
}
return result;
}
function sumOf(objectList, property, index) {
var result = 0;
for (var o in objectList) {
var numbers = (objectList[o][property] || []);
if (numbers.length >= index) {
result += parseInt(numbers[index], 10);
}
}
return result;
}
Using this mini api you can get the sum of the properties you're interested in:
// Get the data array.
var comprehension = extractComprehension(data);
// Sum some property.
console.log(sumOf(comprehension, 'damage', 3));

how to parse json string contains circular reference in javascript?

I have the following json string in javascript. This string contains a circular references. I want to parse this string in such a way that the reference will be replaced by its actual object. I use Json.Parse but it creates the json object with references. Is there any way by whihc i can achieve this ?
{
"$id": "1",
"$values": [
{
"$id": "2",
"Event": {
"$id": "3",
"Invitaions": {
"$id": "4",
"$values": [
{
"$ref": "2"
},
{
"$id": "5",
"Event": {
"$ref": "3"
},
"Id": 2,
"Name": "test2",
"Date": "24",
"EventId": 1
}
]
},
"Id": 1,
"Name": "marriage",
"Address": "abcd"
},
"Id": 1,
"Name": "test1",
"Date": "23",
"EventId": 1
},
{
"$ref": "5"
},
{
"$id": "6",
"Event": {
"$id": "7",
"Invitaions": {
"$id": "8",
"$values": [
{
"$ref": "6"
}
]
},
"Id": 2,
"Name": "birthday",
"Address": "abcd"
},
"Id": 3,
"Name": "test3",
"Date": "25",
"EventId": 2
}
]
}
This should do it:
function resolveReferences(json) {
if (typeof json === 'string')
json = JSON.parse(json);
var byid = {}, // all objects by id
refs = []; // references to objects that could not be resolved
json = (function recurse(obj, prop, parent) {
if (typeof obj !== 'object' || !obj) // a primitive value
return obj;
if ("$ref" in obj) { // a reference
var ref = obj.$ref;
if (ref in byid)
return byid[ref];
// else we have to make it lazy:
refs.push([parent, prop, ref]);
return;
} else if ("$id" in obj) {
var id = obj.$id;
delete obj.$id;
if ("$values" in obj) // an array
obj = obj.$values.map(recurse);
else // a plain object
for (var prop in obj)
obj[prop] = recurse(obj[prop], prop, obj)
byid[id] = obj;
}
return obj;
})(json); // run it!
for (var i=0; i<refs.length; i++) { // resolve previously unknown references
var ref = refs[i];
ref[0][ref[1]] = byid[refs[2]];
// Notice that this throws if you put in a reference at top-level
}
return json;
}
You should check out Douglas Crockfords JSON-js repo on github: https://github.com/douglascrockford/JSON-js
There's a cycle.js in there that helps you do exactly what you're looking for.
Look at my post here, I've found some bugs in the code above and there wasn't arrays support, check out my improved version: Resolve circular references from JSON object

javascript traverse json object

I always think it's going to be easy... I plan to use the json below to build router objects. I put a console.log and so I could have a break point spot so I could try to figure out how to access the the object properties from the chrome console. It never goes into the for loop though.
The main question is how to properly turn the JSON into objects and how to access it's properties.
<script type="text/javascript">
$(document).ready(function(){
$.getJSON('JSON/data.json', function(json) {
for (var i=0;i<json.length;i++){
console.log("in for loop");
}
});
});
</script>
{
"_id": {
"$oid": "4f91f2c9e4b0d0a881cf86c4"
},
"DSC21": {
"Router": {
"online": [
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1"
],
"bytes": [
"59.5721304971465",
"17014.1911069063",
"14858.8518936735",
"6875.20981475265",
"15157.6891384625",
"6363.47544785913",
"29446.2111270486",
"11517.9296243171",
"27077.9747917112",
"19867.79381695"
]
}
},
"DSC22": {
"Router": {
"online": [
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1"
],
"bytes": [
"59.5721304971465",
"17014.1911069063",
"14858.8518936735",
"6875.20981475265",
"15157.6891384625",
"6363.47544785913",
"29446.2111270486",
"11517.9296243171",
"27077.9747917112",
"19867.79381695"
]
}
},
"DSC23": {
"Router": {
"online": [
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1"
],
"bytes": [
"59.5721304971465",
"17014.1911069063",
"14858.8518936735",
"6875.20981475265",
"15157.6891384625",
"6363.47544785913",
"29446.2111270486",
"11517.9296243171",
"27077.9747917112",
"19867.79381695"
]
}
},
"DSC24": {
"Router": {
"online": [
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1",
"1"
],
"bytes": [
"59.5721304971465",
"17014.1911069063",
"14858.8518936735",
"6875.20981475265",
"15157.6891384625",
"6363.47544785913",
"29446.2111270486",
"11517.9296243171",
"27077.9747917112",
"19867.79381695"
]
}
}
}
The variable json is already an object, but it is not an array, so a typical for-loop is insufficient. Since json.length is undefined, i<json.length fails on the first iteration and you skip over the loop.
for (var key in json) {
// key is your DSCxxx
// json[key] is the corresponding object
}
JSON is natively available in JavaScript, you traverse it like you would traverse any object or array.
json["DSC21"]["Router"]["online"][0]; // 1
json.DSC21.Router.online[0]; // equivalent
json.DSC21.Router.online.0; // INCORRECT
If you don't know the names of the properties and want to loop through them use the for .. in construction:
for (var key in json) {
console.log(key); // _id, DSC21, DCS22 etc..
console.log(json[key]); // { "$oid": "" }, { "Router": ".." } etc.
}
This does leave the hasOwnProperty issue, but it shouldn't be a problem if you're just reading JSON data.
maybe you want to know how to iterate your objects?
here would be how to do that:
for( var key in json ){
if( key != '_id'){
var router = json[key].Router;
for( var i = 0; i < router.online.length; i++ ){
console.log(i + ' is online: ', router.online[i]==1?'true':'false');
}
etc...
}
}

Categories