This question already has an answer here:
Recursively list all object property paths from JSON [duplicate]
(1 answer)
Closed 6 years ago.
need some help.
I have a json object and I want to create an string array with keys of the object.
json Object
{
"FEATURES": {
"APP_DASHBOARD": {
"MENU_TITLE": "Dashboard",
"HEAD_TITLE": "Dashboard",
"HEAD_DESC": "Welcome to briteplan"
},
"APP_TEAM": {
"MENU_TITLE": "Teams",
"HEAD_TITLE": "Teams",
"HEAD_DESC": "",
"TOOL_TIPS": {
"TEAM_REFRESH": "Refresh teams",
"TEAM_ADD": "Add new team",
"TEAM_EDIT": "Edit team",
"TEAM_REMOVE": "Remove team",
"MEMBER_REMOVE" : "Remove team member",
"MEMBER_LEAD" : "Team lead",
"AVL_MEMBERS_REFRESH" : "Refresh available members"
},
"CONTENT": {
"TEAMS_TITLE": "Teams",
"MEMBERS_TITLE": "Members",
"AVL_MEMBERS_TITLE": "Available team members"
}
}
},
"GENERAL": {
"SEARCH_PLACEHOLDER": "Search ..."
}
}
I would like to generate a array that looks like this:
var myArray = [
'FEATURES.APP_TEAM.MENU_TITLE',
'FEATURES.APP_TEAM.HEAD_TITLE',
'FEATURES.APP_TEAM.HEAD_DESC',
'FEATURES.APP_TEAM.TOOL_TIPS.TEAM_REFRESH',
'FEATURES.APP_TEAM.TOOL_TIPS.TEAM_ADD',
'FEATURES.APP_TEAM.TOOL_TIPS.TEAM_EDIT',
'FEATURES.APP_TEAM.TOOL_TIPS.TEAM_REMOVE',
];
Not all values is included, but I think you get the Idea. The main thing is I Will know the I have "FEATURES" in the object and I will know the feature name "APP_TEAM", but I don't know the nesting level within that feature.
Hope anyone can help me.
recursion:
function getKeys (o) {
var keys = [];
for (var prop in o) {
if(o.hasOwnProperty(prop)) {
if(typeof o[prop] === 'object') {
getKeys(o[prop]).forEach(function (nestedProp) {
keys.push(prop + '.' + nestedProp);
});
}
else {
keys.push(prop);
}
}
}
return keys;
}
on the above object, returns:
[
"FEATURES.APP_DASHBOARD.MENU_TITLE",
"FEATURES.APP_DASHBOARD.HEAD_TITLE",
"FEATURES.APP_DASHBOARD.HEAD_DESC",
"FEATURES.APP_TEAM.MENU_TITLE",
"FEATURES.APP_TEAM.HEAD_TITLE",
"FEATURES.APP_TEAM.HEAD_DESC",
"FEATURES.APP_TEAM.TOOL_TIPS.TEAM_REFRESH",
"FEATURES.APP_TEAM.TOOL_TIPS.TEAM_ADD",
"FEATURES.APP_TEAM.TOOL_TIPS.TEAM_EDIT",
"FEATURES.APP_TEAM.TOOL_TIPS.TEAM_REMOVE",
"FEATURES.APP_TEAM.TOOL_TIPS.MEMBER_REMOVE",
"FEATURES.APP_TEAM.TOOL_TIPS.MEMBER_LEAD",
"FEATURES.APP_TEAM.TOOL_TIPS.AVL_MEMBERS_REFRESH",
"FEATURES.APP_TEAM.CONTENT.TEAMS_TITLE",
"FEATURES.APP_TEAM.CONTENT.MEMBERS_TITLE",
"FEATURES.APP_TEAM.CONTENT.AVL_MEMBERS_TITLE",
"GENERAL.SEARCH_PLACEHOLDER"
]
Related
const gyms = [
{
"name": "gym1",
"equipment": ["nothing"]
},
{
"name": "gym2",
"equipment": ["barbell", "kettlebell"]
},
{
"name": "gym3",
"equipment": ["barbell","dumbbell","jump rope"]
}
]
equipmentNeeded = ["barbell","jump rope"]
I have an object (gyms) that contains all available equipment.
I also have an array (equipmentNeeded) that contains all the equipment I need a gym to have so I know if I should go or not.
I can get it to work if a variable is a single word string (i.e. I choose only a single piece of equipment), but I'm stuck on if I have multiple values to compare.
This is where I'm at, currently:
for (i=0;i < gyms.length; i++) {
if (gyms[i]["equipment"].includes(equipmentNeeded)) {
console.log(gyms[i]["type"] + " has all needed equipment")
} else {
console.log(gyms[i]["type"] + " doesn't have needed equipment")
}
}
Modify your code to this:
for (i=0;i < gyms.length; i++) {
if(equipmentNeeded.every(eq => gyms[i]["equipment"].includes(eq))) {
console.log(gyms[i]["type"] + " has all needed equipment")
} else {
console.log(gyms[i]["type"] + " doesn't have needed equipment")
}
}
You can use a function like that to check whether an array of some strings includes all the other ones:
function checkEquipment(itemsOwned, itemsNeeded) {
for(let itemNeeded of itemsNeeded) {
if(!itemsOwned.includes(itemNeeded)) {
return false;
}
}
return true;
}
Now you can iterate over all gyms to check if some of them suits you or not:
const gyms = [{
"name": "gym1",
"equipment": ["nothing"]
},
{
"name": "gym2",
"equipment": ["barbell", "kettlebell"]
},
{
"name": "gym3",
"equipment": ["barbell", "dumbbell", "jump rope"]
}
]
const equipmentNeeded = ["barbell", "jump rope"];
function checkEquipment(itemsOwned, itemsNeeded) {
for (let itemNeeded of itemsNeeded) {
if (!itemsOwned.includes(itemNeeded)) {
return false;
}
}
return true;
}
for (let gym of gyms) {
if (checkEquipment(gym.equipment, equipmentNeeded)) {
console.log(gym.name + " has all needed equipment")
} else {
console.log(gym.name + " doesn't have needed equipment")
}
}
You could do it in the following way -
Working Code -
const gyms = [
{
"name": "gym1",
"equipment": ["nothing"]
},
{
"name": "gym2",
"equipment": ["barbell", "kettlebell"]
},
{
"name": "gym3",
"equipment": ["barbell","dumbbell","jump rope"]
}
]
const equipmentNeeded = ["barbell","jump rope"]
const filteredGyms = gyms.filter((gym) => {
return equipmentNeeded.every(e => gym.equipment.includes(e));
});
console.log(filteredGyms)
Explanation
The above code just maps through each element in gyms and for each element(I have named it gym used in filter function) it checks whether every element inside equimentNeeded (using every() which just checks whether all elements in the array pass the test implemented by the provided function) is present inside the gym (<- which current element under iteration).
Lastly, the whole code will return you a filteredGym array which will just be including the gyms that fit or match your requirements.
equipmentNeeded.every(e => gym.equipment.includes(e));
The above statement just returns a boolean value specifying whether the current object of gyms array is having all the equipmentNeeded. If the boolean is true, the current object is included in filteredGyms or else it is filtered out.
I would suggest you to avoid using direct for-loops in JS unless its totally needed (there's nothing bad to it but its better to use other in-built methods provided by JS like map, filter, reduce, etc which would get most of the job done).
You could use every. Here's an example:
const gyms = [
{
"name": "gym1",
"equipment": ["nothing"]
},
{
"name": "gym2",
"equipment": ["barbell", "kettlebell"]
},
{
"name": "gym3",
"equipment": ["barbell","dumbbell","jump rope"]
}
]
const equipmentNeeded = ["barbell","jump rope"];
gyms.forEach(gym => {
if (equipmentNeeded.every(i => gym.equipment.includes(i))) {
console.log(gym.name + " has all needed equipment");
} else {
console.log(gym.name + " doesn't have needed equipment");
}
});
This question already has answers here:
Accessing a JavaScript's object property without knowing that property name
(3 answers)
How to access the first property of a Javascript object?
(23 answers)
Getting the first index of an object
(14 answers)
Closed 3 years ago.
I'm calling an API in my application and need to drill down the JSON response. Within it there is a random string that changes so I can't hardcode the value. Is there a way I can access dataset1 no matter what the random string is?
{
"data": {
"Random String that Changes": {
"dataset1": {
"date": {...}
},
"dataset2":{
"date": {...}
}
}
},
"something else": {
...
},
"something else": {
...
}
}
Previously I was hard coding the drill down like such:
this.props.data.randomData['Random String that Changes'].dataset1.date
Also tried:
this.props.data.randomData[0].dataset1.date
You can get all the keys of the object using
const keys = Object.keys(this.props.data);
Now keys is an array of all keys , but if you json always only has 1 key, you can get your data using
this.props.data.randomData[keys[0]].dataset1.date
You can get dataset1
const values = Object.values(this.props.data)
console.log(values[0]['dataset1'])
Make sure that your json includes the "Random String that changes" at first place as shown in your above format.
Reference: Object.values
Try accessing the object like this :
const obj = this.props.data;
obj[Object.keys(obj)[0]].dataset1.date
Reference: How to access the first property of an object in Javascript?
Consider sample data in myObj.
var myObj = {
"data" : {
"Random String that Changes": {
"dataset1": {
"date": "123"
},
"dataset2":{
"date": "123"
}
}
}
}
var randomString =myObj[Object.keys(myObj)[0]];
var dataset1Date =randomString[Object.keys(randomString)[0]].dataset1.date;
console.log(dataset1Date);
So in this way you can access the date which you are trying with
this.props.data.randomData['Random String that Changes'].dataset1.date
Please check the below code for the solution.
var response = {
"data": {
"Random String that Changes": {
"dataset1": {
"date": {...}
},
"dataset2":{
"date": {...}
}
}
},
"something else": {
...
},
"something else": {
...
}
};
var dataInRandomKey = response.data[Object.keys(response.data)[0]];
Now, you have the whole JSON object (in current example, response['data']['Random String that Changes']) in dataInRandomKey variable.
You can try for in loop
var a = {
"data": {
"Random String that Changes": {
"dataset1": {
"date": {...}
},
"dataset2":{
"date": {...}
}
}
},
"something else": {
...
},
"something else": {
...
}
}
var response = a.data;
for(var key in response) {
console.log(response[key].dataset1);
}
I'm new to software Field. i have a json array of objects like
var treeObj = [
{
"name": "sriram",
"refernce_id": "SAN001",
"sponer_id": "SAN000"
},
{
"name": "neeraja",
"refernce_id": "SAN002",
"sponer_id": "SAN001"
},
{
"name": "upender",
"refernce_id": "SAN003",
"sponer_id": "SAN001"
},
{
"name": "manoj",
"refernce_id": "SAN004",
"sponer_id": "SAN002"
},
{
"name": "shirisha",
"refernce_id": "SAN005",
"sponer_id": "SAN002"
},
{
"name": "ragu",
"refernce_id": "SAN006",
"sponer_id": "SAN003"
},
{
"name": "santhu",
"refernce_id": "SAN007",
"sponer_id": "SAN003"
}
];
Here i will pass the above object to a function. in that function i need to compare reference id with sponer_id in every object and if they are equal we need to push them into an Array which we call as child object just like below and again we need to check in the child Array that the reference id in is present in sponer_id of above object if it is present again we need to push them to child array into object which contains the reference_id. the final array Object looks like.
[
{
"name": "sriram",
"parent": null,
"children": [
{
"name": "neeraja",
"parent": "sriram",
"children": [
{
"name": "manoj",
"parent": "neeraja"
},
{
"name": "shirisha",
"parent": "neeraja"
}
]
},
{
"name": "upender",
"parent": "sriram",
"children": [
{
"name": "ragu",
"parent": "neeraja"
},
{
"name": "santhu",
"parent": "neeraja"
}
]
}
]
}
]
Here sriram's reference id of treeObj is present as sponer id in neeraja and upender object. so neeraja and upender becomes child to sriram. and neeraja's reference_id is present as sponer_id in manoj and shirisha objects of treeObj. simultaneously the child can many more child objects and we need to format the object dynamically.
The function which i wrote looks like
var mainArr = [], subArrs = [], subObj={}, subIds = [], find = "SAN001";
formatData(treeObj);
function formatData(treeObj){debugger;
var arr = [];
for(var x=0; x<= treeObj.length-1; x++){debugger;
var sampData = treeObj[x];
if(find == sampData.sponer_id){
arr.push(sampData.refernce_id);
subArrs.push(sampData);
}
}
subIds.push(arr);
console.log(subIds);
console.log(subArrs);
formatData(subArrs);
}
please guide me where i went wrong. thanks in advance.
//1. find all items the have no parent and push them on a stack like so:
let stack = treeObj.reduce((list, item) => {
if (<ids match>) list.push(item);
return item;
}, []),
let result = [].concat(stack);
//2. while loop the stack:
while (stack.length > 0) {
let item = stack.shift();
item.children = treeObj.reduce((list, child) => {
if (<ids match>) {
list.push(child);
}
return list;
}, []).map(child => {
child.parent = item;
stack.unshift(item);
return child;
});
}
return result;
UPDATE
So in »good old JS« and with some improvements:
var stack = treeObj.filter(function (item) {
return item.<parent_id> === item.<child_id> });
var result = [].concat(stack);
while (stack.length > 0) {
var item = stack.shift();
item.children = treeObj.filter(function (child) {
return item.<id> === child.<parent_id>;
});
item.children.forEach(function (child) { stack.unshift(child) });
}
Basically:
find the root(s) and save them on the stack
while.length > 0
shift() the first item from the stack
find all children of that item and unshift them on the stack
Done
Adding a parent property to the items, or removing unneeded one, can be done in the loop. The whole thing can also be done using recursion, but I once ran in the »too much recursion error« by doing such stuff, so I prefer an iterative approach. And of course, instead of .reduce, .filter and .forEach, you can use regular loops, but I prefer a functional style. All in all, no matter how you do it, it is not that difficult, just find the elements to start with and then repeat with all of their children and so on. Withing the while loop all children are found, or, the whole subtree with that element as root.
Good luck!
You're basically trying to convert an array to a n-ary tree.
Entering your original tree function into formatData gives you an array (arr) with the referenceIDs of all objects having SAN001 as parent and another array (subArrs) with all children of with sponerId SAN001.
You then store the arr in subIds, log subIds and subArr and proceed to call format data on subArrs recursively. Then you check on subArr which objects have "SAN001 as predecessor" (which should be all objects at that time) and push that object in subArr. If im not getting it wrong this leads to an infinite loop.
Starting points for improvements:
you're "find" variable does not change, it's hardwired to "SAN001" - this would maybe be okay for your first trip when you're 100% sure that the root object has always this referenceID. But in the second trip, you want to check which objects depend on a second level element, so you need to set find to an corresponding referenceId.
Your subArrs contains all objects depending on SAN001. But in the second and following trips, you don't want to get childrens of SAN001 but child of objects in the subArr. So you need to travers old objects finding children of objects in subArr instead of traversing subArr seeking children of SAN001.
Hope that clear's it up a little bit.
A hint for further research: You're basically trying to "convert an array into a n-ary tree" with javascript.
I've followed Martin Liversaege's answer from this question on Stack Overflow: What is the implementing class for IGrouping?
I've implemented my own class that derives from IGroupable as such:
public class AjaxResponseGroup<TKey, TElement> : IGrouping<TKey, TElement>
{
readonly List<TElement> elements;
public AjaxResponseGroup(IGrouping<TKey, TElement> ajaxResponseGroup)
{
if (ajaxResponseGroup == null)
{
throw new ArgumentNullException("ajaxResponseGrouping");
}
Key = ajaxResponseGroup.Key;
elements = ajaxResponseGroup.ToList();
}
public TKey Key { get; private set; }
public IEnumerator<TElement> GetEnumerator()
{
return this.elements.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
I've got this fun little LINQ statement in my controller:
var groupedAuthActions = unitOfWork.AuthActions.GetAll()
.WhereIf(q != null, x => x.Name.ToLower().Contains(q.ToLower()))
.OrderByDescending(authAction => authAction.CreatedOn)
.Select(authAction => new AuthActionsListViewModel
{
Id = authAction.Id.ToString(),
Name = authAction.Name,
Description = authAction.Description,
Grouping = authAction.Grouping
})
.GroupBy(authActions => authActions.Grouping)
.Select(g => new AjaxResponseGroup<string, AuthActionsListViewModel>(g))
.ToList();
Which is serialized with the following line:
string serializedObject = JsonConvert.SerializeObject(groupedAuthActions);
However, when that is converted to JSON, the key is not included in the string, instead, the groups are anonymous arrays:
[
[{
"Id": "5fb20278-2f5e-4341-a02d-070d360066cd",
"Name": "CreateAuthAction",
"Description": "Allows the user to create an AuthAction",
"Grouping": "User Management"
}, {
"Id": "1edc56d4-9529-4a18-8684-137d0ccfd4d3",
"Name": "ReadAuthAction",
"Description": "Allows the user to view the AuthActions within the system",
"Grouping": "User Management"
}],
[{
"Id": "f1332b37-44c2-4c86-9cbe-ea3983bf6dfe",
"Name": "DeleteAuthAction",
"Description": "Allows the user to delete an AuthAction",
"Grouping": "Test Group"
}]
]
Other than looking at the Grouping property of the first item in the array, how am I to determine what the key of the group is when using the object in the front-end JavaScript?
Is the only/best solution to do something like: (I'd be doing iterative functions, but to illustrate the idea)
// myObj = JS Object from return JSON above
var firstGroup = myObj[0][0].Grouping;
I feel like there has to be a more elegant and "correct" way of doing things?
I want to compare the data.examples array object name.value property value with wcObject.notCoveredList key, If the key matches I want to push all matched values of wcObject to an array inorder to display in UI. If the key doesn't match, I want the name.desc property value of data.examples array object to be pushed by removing the not covered text at the end.
data = {
examples : [
{
name: {
value:"someOne",
desc: "some random word not covered"
},
type: {
value:"General",
desc:"General"
}
}, {
name: {
value:"secondOne",
desc: "second on in the queue not covered"
},
type: {
value:"General",
desc:"General"
}
}, {
name: {
value:"thirdOne",
desc: "third one from the last not covered"
},
type: {
value:"General",
desc:"General"
}
}
]
}
wcObject = {
notCoveredList : [
{ someOne: "anyone can start " },
{ secondOne: "second One cannot start" },
{ thirdOne: "third One can be allowed" }
]
}
So, this code:
Builds up a filter object. We grab all the keys of
wcObject.notCoveredList, and make them keys on a single object (with
an undefined value), so that we can look up those keys with a single
hasOwnProperty() call instead of iterating over an array when we need to filter.
Maps every member of the data.examples array to either its own name.desc property or [stripped of ' not covered'] name.value property.
.
wcNotCoveredKeys = wcObject.notCoveredList.reduce((memo, item) => {
// value is empty for all, we only care about keys.
memo[Object.keys(item)[0]] = undefined;
return memo;
}, {})
// having built up our lookup table of those not covered, we continue:
forUI = data.examples.map(example => {
if (wcNotCoveredKeys.hasOwnProperty(example.name.value)) {
return example.name.value;
}
else {
notCoveredString = example.name.desc;
cutOutIndex = notCoveredString.indexOf(' not covered');
return notCoveredString.slice(0, cutOutIndex)
}
});
(updated to integrate string slicing)
Just to be clear: if you removed the second item from wcObject.notCoveredList, then the output you'd get in forUI (given the example data structures/values you provided) would be
["someOne", "second on in the queue", "thirdOne"]