I am pretty new to JavaScript. I have a nested object and I want to be able to reorder the key/value pairs. I tried looking for a solution at a lot of places online but mostly found answers to sort a 2-D array, nothing with this complexity level.
My object looks something like this:
id:{
Category1 : {
a : {count:1, volume:5}
b : {count:2, volume:10}
}
Category2: {
a : {count:4, volume:8}
b : {count:10, volume:4}
}
}
and I want to sort it on the basis of the name instead of category. Intedend result:
id:{
a : {
Category1 : {count:1, volume:5}
Category2 : {count:4, volume:8}
}
b: {
Category1 : {count:2, volume:10}
Category2 : {count:10, volume:4}
}
}
You can do it using
let id = {
Category1 : {
a : {count:1, volume:5},
b : {count:2, volume:10}
},
Category2: {
a : {count:4, volume:8},
b : {count:10, volume:4}
}
}
for(obj in id){
for(obj2 in id[obj]){
id[obj2] = id[obj2] || {};
id[obj2][obj] = id[obj][obj2];
}
delete id[obj];
}
console.log(id);
in this code
for(obj in id)
traverses all properties of id so obj would be in the set {"Category1", "Category2"} and id[obj] would refer to the sub object
for(obj2 in id[obj])
traverses the property of the sub object and so obj2 would be in the set {"a", "b"}
id[obj2] = id[obj2] || {};
initialises the new property of id if it doesn't already exist i.e id["a"] and id["b"]
id[obj2][obj] = id[obj][obj2];
assigns the sub sub object ({count:1, volume:5}) to the new property within the sub property obj
delete id[obj];
lastly delete the current property since it is not of use anymore
Related
I have a class definition…
class anObj {
"ID" : string;
dialog: {[id : number]:{hide: boolean;}} = {
0 : {"hide": false},
14 : {"hide": false}
}
}
class manyObjects {
myGroup: anObj [] = [];
}
...
public stuff = manyObjects;
This totally works just the way I'd like for it to...I can use the id value as a direct key...
var x:number = 1 //used for a different tier of logic
stuff.myGroup[x].dialog[14].hide!=true
Here's where I'm stuck... I'd like to add more dialogs to the group. I get all the way our to...
stuff.myGroup[x].dialog
and can't figure out how to add something like with a push...
.push(7 : {"hide": true})
for example, I can type this line and the IDE says it's ok...
stuff.myGroup[x].dialog[[id=7].push({"hide": false})];
however, when I check, the element does not get added to the array...
What I could gather from your code is that you're trying to add a new dialog to the object contained in the "dialog" property of anObj, which is not an array. It's an object with an expected structure in typescript: every property of that object should be a number, and the value of every property should be of type {hide: boolean;}.
From there, it's quite easy, you add a new property (or overwrite an existing one) as you do for any JS object:
stuff.myGroup[x].dialog[7] = {hide: false};
Again, stuff.myGroup[x].dialog is an object, not an array, the array is stuff.myGroup.
If you want to add another "group" to myGroup then you'd do something like:
stuff.myGroup.push(new anObj());
EDIT
Example that ignores the noise created by extra objects like stuff and my group, but demonstrates adding a new key-value pair:
class anObj {
"ID" : string;
dialog: {[id : number]:{hide: boolean;}} = {
0 : {"hide": false},
14 : {"hide": false}
}
}
class manyObjects {
myGroup: anObj [] = [];
}
var obj = new anObj();
obj.dialog[7] = { hide: true };
console.log(obj);
You can try that in typescript playground -> https://www.typescriptlang.org/play/?ssl=14&ssc=18&pln=1&pc=1#code/MYGwhgzhAEYHYHkBGAraBvaAoa0BEAkgCJ7QBc0EALgE4CWcA5gNw7QAmdYIA9oxegDadduWhwArgFskAUxoBdMugAWI2RSQ8eIWfGYBfA9AC8GNrgAMY9HjXtZeCgDNuEWQYA0F6AEYALDZ26k7QriDuBmzGuNhRoJAwUvAAnsgossBUMOhsUikA4jQ8EgAOFPDp0IIKptUKrFFYAG5gNNA8qHVwsgDusIioABQAlKydKAB0nNx8ggDstWaY9hrQtBKy0AaswDxwEDqyk7yMQxNjQA
Update 2
To return the enumerable keys of an object, you can use the Object.keys method. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
console.log(Object.Keys(obj));
I am using two different array object initialPermissionArr[item.id] and newPermissionArr[roleId] in two different functions
function(item){
vm.initialPermissionArr[item.id] = item.permissions.map(function (permission) {
permission.status = true;
return permission;
});
}
staticArr[item.id] = item.permissions.map(function (permission) {
permission.status = true;
return permission;
});
newpermissionArr[item.id] = vm.initialPermissionArr[item.id];
Below function updates the array, if same object is found it updates the status and if new object is found it pushes to newPermissionArr
function onChanageOfPermission(roleId,item) {
var flag = false ;
for (var key in newpermissionArr[roleId]){
if(newPermissionArr[roleId][key].id == item.id){
flag = true;
newPermissionArr[roleId][key].status = item.status;
break;
}
}
if (!flag) {
newPermissionArr[roleId].push(item);
}
}
So when newPermissionArr[roleId][key].status = item.status; is updated it also update the status in the initialPermissionArr[item.id] also.
And initial declaration is
var newPermissionArr = [];
var staticArr = [];
where for eg item is
{
roleId : 1,
permissions : [{"name": "A", "id" : 1},{ "name" : "B", "id" : 2 }]
}
I need initial object Array to remain same and at the end i need to compare the initial array with the modified array and need to find the reference however on updating the status it updates in both array. How to avoid this ?
The arrays reference the same object. To modify just one of them, you should use slice() function for clone the array:
newpermissionArr[item.id] = vm.initialPermissionArr[item.id].slice();
This is happening because of following line of code
newpermissionArr[item.id] = vm.initialPermissionArr[item.id];
Here object is passed by reference, so whenever newpermission is updated intialpermission will also be updated.
To fix this just copy the intialPermissionArr to newPermissionArr.
Unfortunately,plain javascript does not have any function like angular.copy. So you will have to do this in following way-
newrPermissionArr[item.id] = JSON.parse(JSON.stringify(vm.intialPermissionArr[item.id]));
this should fix your problem.
When you assign something to a and b and it is a pointer in memory to object c. Then as soon as you change it to c2 both a and b will get c2 from that point as they were just pointers to same location.
I am trying to wrap my head around how I might accomplish something like this, structurally:
var keywordDataProducts =
[
{"keyword" : "keyword1", "list" : [ "DP1", "DP2" ] },
{"keyword" : "keyword2", "list" : [ "DP1" ] }
];
But of course, without the values being hard coded. For instance, we currently loop through all the DP values (DP1, DP2, DP3, etc..) - which all have 0-M keywords. I'm trying to create an inverse lookup of that, where you can get all DPs that use a particular keyword. I have code that uses the structure above perfectly, but I just need the data to get populated more dynamically.
Do I initialize the var keywordDataProducts = []; declaration with anything in it, or define the structure of it having a keyword and a list (which is an array)? Or do you leave it as an array with nothing about it, and define that when you're adding items?
I've heard associative arrays can be used for a situation like this, but I'm not quite wrapping my head around that at the moment. I've also seen objects with {} usages, but there is no push there and I need an array of keywords, which also contains arrays of DPs (list). Thoughts?
You would do something like this, but you didn't clearly describe what the input look like and what output you're looking for.
function fn (input) {
var ouput = {};
input.forEach( function (DP) {
for (prop in DP) {
if (DP.hasOwnProperty(prop) {
if (output[prop]) {
output[prop].push(DP);
} else {
output[prop] = [DP];
}
}
}
});
return output;
}
This takes this kind of input
[{"alpha":...}, {"beta":..., "delta":...}, {"alpha":..., "gamma":...}]
and returns
{"alpha":[{"alpha":...}, {"alpha":..., "gamma":...}]}, "beta":{"beta":..., "delta":...}, "delta":{"beta":..., "delta":...}, "gamma":{"alpha":..., "gamma":...}}
I don't know how you want your output so I just made an object with each keyword as its own key for the DP values.
var data = [{dp: "dp1", keys: ["key1", "key2", "key3"]}, {dp: "dp2", keys: ["key1", "key2", "key3"]}, {dp: "dp3", keys: ["key1", "key2", "key3"]},];
function keyWordArray(arr) {
var newObj = {};
arr.forEach((obj) => {
obj.keys.forEach((keyVal) => {
if(newObj.hasOwnProperty(keyVal)){
newObj[keyVal].dp.push(obj.dp);
} else {
newObj[keyVal] = {dp:[obj.dp],};
}
});
});
return newObj;
}
document.getElementById("data").innerHTML = JSON.stringify(keyWordArray(data));
<div id="data">
</div>
You can treat objects as associative arrays, and you don't have to use "push" to add a new element.
// Create your object like this
var keywordDataProducts =
{
"keyword1" : { "list" : [ "DP1", "DP2"] },
"keyword2" : { "list" : [ "DP1" ] }
};
// Treat it like an associative array
var keyword1 = keywordDataProducts["keyword1"];
alert("keyword1 = " + keyword1.list.join(", "));
// Add to it like this
keywordDataProducts["keyword3"] = { "list" : ["DP3", "DP4"] };
// See the new object includes your new keyword
alert(JSON.stringify(keywordDataProducts));
// To iterate the keys of your object, you can do something like this
for(var item in keywordDataProducts)
{
if(keywordDataProducts.hasOwnProperty(item))
{
alert(item);
}
}
You can see the fiddle here;
https://jsfiddle.net/gksjtwr6/2/
I have a JSON file like below:
[
{"fields":{category_class":"CAT2",category_name":"A"},"pk":1 },
{"fields":{category_class":"CAT1",category_name":"B"},"pk":2 },
{"fields":{category_class":"CAT1",category_name":"C"},"pk":3 },
{"fields":{category_class":"CAT2",category_name":"D"},"pk":4 },
{"fields":{category_class":"CAT3",category_name":"E"},"pk":5 },
{"fields":{category_class":"CAT1",category_name":"E"},"pk":6 },
]
I want to create an array of objects from the above JSON which will have two properties. i) CategoryClass ii) CategoryNameList. For example:
this.CategoryClass = "CAT1"
this.CategoryNameList = ['B','C','E']
Basically i want to select all categories name whose category class is CAT1 and so forth for other categories class. I tried this:
var category = function(categoryClass, categoryNameList){
this.categoryClass = categoryClass;
this.categoryList = categoryNameList;
}
var categories = [];
categories.push(new category('CAT1',['B','C','E'])
Need help.
You can use a simple filter on the array. You have a few double quotes that will cause an error in you code. But to filter only with CAT1 you can use the filter method
var cat1 = arr.filter( value => value.fields.category_class === "CAT1");
I would suggest this ES6 function, which creates an object keyed by category classes, providing the object with category names for each:
function groupByClass(data) {
return data.reduce( (acc, { fields } ) => {
(acc[fields.category_class] = acc[fields.category_class] || {
categoryClass: fields.category_class,
categoryNameList: []
}).categoryNameList.push(fields.category_name);
return acc;
}, {} );
}
// Sample data
var data = [
{"fields":{"category_class":"CAT2","category_name":"A"},"pk":1 },
{"fields":{"category_class":"CAT1","category_name":"B"},"pk":2 },
{"fields":{"category_class":"CAT1","category_name":"C"},"pk":3 },
{"fields":{"category_class":"CAT2","category_name":"D"},"pk":4 },
{"fields":{"category_class":"CAT3","category_name":"E"},"pk":5 },
{"fields":{"category_class":"CAT1","category_name":"E"},"pk":6 },
];
// Convert
var result = groupByClass(data);
// Outut
console.log(result);
// Example look-up:
console.log(result['CAT1']);
Question : Basically i want to select all categories name whose category class is CAT1 and so forth for other categories class
Solution :
function Select_CatName(catclass,array){
var CatNameList=[]
$(array).each(function(){
if(this.fields.category_class==catclass)
CatNameList.push(this.fields.category_name)
})
return CatNameList;
}
This function return the Desired Category Name List, you need to pass desired catclass and array of the data , as in this case it's your JSON.
Input :
Above function calling :
Output :
Hope It helps.
I have an Angular controller that defines a scoped variable that consist of an array of objects. Each object is a tagName and its value is a list of services associated to those tags:
$scope.recordedServices = [{"myTag" : [{ url : "http://service0"}, { url : "http://service1" }] }];
After the page is loaded {{recordedServices}} prints correctly:
[{"myTag":[{"url":"http://service0"},{"url":"http://service1"}]}]
In that controller I have a replaceList function that replaces the whole $scoped.recordedServices list:
$scope.replaceList = function(){
$scope.recordedServices = [ {"myTag" : [{url:"http://replacedList"}] }];
}
When calling it, everything works as expected, {{recordedServices}} is now:
[{"myTag":[{"url":"http://replacedList"}]}]
Now the problem. What I really want to do is add a new service to "myTag":
$scope.addToList = function(){
$scope.recordedServices["myTag"].push({url:"http://addedService"});
}
But it fails because $scope.recordedServices["myTag"] doesn't exist, the actual structure of the $scoped.recordedServices list is:
$scope.recordedServices: Array[1]
0 : Object
$$hashKey : "object:33"
myTag : Array[1]
0 : Object
$$hashKey : "object:36"
url : "http://replacedList"
What is the correct (Angular) way to add an element to that array?
UPDATE:
One possible solution would be doing:
$scope.addToList2 = function(){
if($scope.recordedServices[0] == null){
$scope.recordedServices[0] = [];
}
if($scope.recordedServices[0]["myTag"] == null){
$scope.recordedServices[0]["myTag"] = [];
}
$scope.recordedServices[0]["myTag"].push({url:"http://addedService"});
}
But this works only if $scope.recordedServices was initialized in the controller (for instance: $scope.recordedServices = [{"myTag" : [{ url : "http://service0"}, { url : "http://service1" }] }];). However if initially it is $scope.recordedServices = [] it doesn't work.
{{recordedServices}} prints [[]]
Inspecting the variable the content is as follows. It looks similar with the only differenced that myTag[0] doesn't contain $$hashKey.
$scope.recordedServices: Array[1]
0 : Array[0]
$$hashKey : "object:68"
length : 0
myTag : Array[1]
0 : Object
url : "http://addedService"
$scope.recordedServices is an array. You should use an index:
Change this:
$scope.recordedServices["myTag"].push({url:"http://addedService"});
to this:
$scope.recordedServices[0]["myTag"].push({url:"http://addedService"});
UPDATE
You can check if it is empty, if so, add myTag object too:
if ($scope.recordedServices.length == 0){
$scope.recordedServices.push({"myTag": [{url:"http://addedService"}]});
}else{
$scope.recordedServices[0]["myTag"].push({url:"http://addedService"});
}
You can define your $scope.recordedServices=[] as an empty array inside your controller. So now you can play with it inside the controller and view as you wish.
Push new record like this -
$scope.addToList = function(){
$scope.recordedServices.push({url:"http://addedService"});
}