I'm trying to build a new object from an old object recursively like:
var arr = {};
var markCheckBoxes = function(obj){
var trackArr = new Array();
for(var prop in obj){
if(!!obj[i] && typeof(obj[i])=="object"){
trackArr.push(i);
markCheckBoxes(obj[i]);
trackArr.pop();
}
else{
var str = trackArr.join(".") + "." + i;
arr[str] = true;
}
}
};
But this creates a flat object. For example if obj is:
obj = {
prop1: {
subprop1: "text",
subprop2: "extra"
}, prop2:{
subprop: {another: 3}
}
}
Then the above function creates an object with keys:
{
"prop1.subprop1": true,
"prop1.subprop2": true,
"prop2.subprop.another": true
}
Assuming OP want to make other copy of object with true value for the keys, you can modify the code as below
var makeChecks = function(obj){
var cloneTo = {};
for(var prop in obj){
if(obj.hasOwnProperty(prop) && typeof(obj[prop]) === 'object'){
cloneTo[prop] = makeChecks(obj[prop]);
}
else{
cloneTo[prop] = true;
}
}
return cloneTo;
}
var obj = {
prop1: {
subprop1: "text",
subprop2: "extra"
}, prop2:{
subprop: {another: 3}
}
}
var output = makeChecks(obj);
console.log(output)
/*
{
"prop1": {
"subprop1": true,
"subprop2": true
},
"prop2": {
"subprop": {
"another": true
}
}
}
*/
Related
I am trying to get a list of tags from an object
Here is the full code and data:
$(document).ready(function() {
obj =
{
"category":[
{
"id":"8098",
"tags":{
"411":"something",
"414":"something else"
}
}
]
};
var tagList = [];
for (var index in obj) {
for (var indexSub in obj[index].tags) {
blah = (obj[index].tags[indexSub]);
tagList.push(blah);
}
}
console.log(tagList);
});
Here's a link to jsFiddle
The problem is that taglist is returning an empty array.
How can I fix this?
Yours
for (var index in obj) {
for (var indexSub in obj[index].tags) {
blah = (obj[index].tags[indexSub]);
tagList.push(blah);
}
}
New to get the tags that are into the category
for (var index in obj) {
for (var indexSub in obj[index]) {
blah = (obj[index][indexSub].tags);
tagList.push(blah);
}
}
See the diference in the way to access the properties
obj =
{
"category": [
{
"id": "8098",
"tags": {
"411": "something",
"414": "something else"
}
}
]
};
var tagList = [];
for (var index in obj) {
for (var indexSub in obj[index]) {
tagList = (obj[index][indexSub].tags);
// tagList.push(blah);
}
}
console.log(tagList);
You need to iterate the category, and then get the keys and values of tags, somethig like this..
var obj =
{
"category":[
{
"id":"8098",
"tags":{
"411":"something",
"414":"something else"
}
}
]};
var tagList = [];
obj.category.forEach( o =>{
for (property in o.tags){
tagList.push(property + ':'+ o.tags[property]);
};
});
console.log(tagList);
Here is your jsfiddle
obj =
{
"category":[
{
"id":"8098",
"tags":{
"411":"something",
"414":"something else"
}
}
]
};
var tagList = [];
for (key in obj) {
for(subKey in obj[key]){
var myTags=obj[key][subKey].tags;
for(tag in myTags){
tagList.push(tag);
}
}
}
console.log(tagList);
You could use Array#reduce and Object.keys with Array#map for iterating and getting all tags.
var obj = { "category": [{ "id": "8098", "tags": { "411": "something", "414": "something else" } }] },
tagList = obj.category.reduce(function (r, a) {
return r.concat(Object.keys(a.tags).map(function (t) { return a.tags[t]; }));
}, []);
console.log(tagList);
I've got the following JSON string:
{
"Alarm":{
"Hello":48,
"World":3,
"Orange":1
},
"Rapid":{
"Total":746084,
"Fake":20970,
"Cancel":9985,
"Word": 2343
},
"Flow":{
"Support":746084,
"About":0,
"Learn":0
}
}
Then I load the above string and convert it to json object:
jsonStr = '{"Alarm":{"Hello":48,"World":3,"Orange":1},"Rapid":{"Total":746084,"Fake":20970,"Cancel":9985},"Flow":{"Support":746084,"About":0,"Learn":0}}';
var jsonObj = JSON.parse(jsonStr);
Now, how can I filter this json object by key name?
E.g., if the filter was "ange", the filtered object would be:
{
"Alarm":{
"Orange":1
}
}
If the filter was "flo", the filtered object would become:
{
"Flow":{
"Support":746084,
"About":0,
"Learn":0
}
}
And if the filter was "wor", the result would be:
{
"Alarm":{
"World": 3,
},
"Rapid":{
"Word": 2343
}
}
Is it possible to achieve this filtering using the filter method?
Beside the given solutions, you could use a recursive style to check the keys.
This proposal gives the opportunity to have more nested objects inside and get only the filtered parts.
function filterBy(val) {
function iter(o, r) {
return Object.keys(o).reduce(function (b, k) {
var temp = {};
if (k.toLowerCase().indexOf(val.toLowerCase()) !== -1) {
r[k] = o[k];
return true;
}
if (o[k] !== null && typeof o[k] === 'object' && iter(o[k], temp)) {
r[k] = temp;
return true;
}
return b;
}, false);
}
var result = {};
iter(obj, result);
return result;
}
var obj = { Alarm: { Hello: 48, "World": 3, Orange: 1 }, Rapid: { Total: 746084, Fake: 20970, Cancel: 9985, Word: 2343 }, Flow: { Support: 746084, About: 0, Learn: 0 }, test: { test1: { test2: { world: 42 } } } };
console.log(filterBy('ange'));
console.log(filterBy('flo'));
console.log(filterBy('wor'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can create a function using reduce() and Object.keys() that will check key names with indexOf() and return the desired result.
var obj = {
"Alarm": {
"Hello": 48,
"World": 3,
"Orange": 1
},
"Rapid": {
"Total": 746084,
"Fake": 20970,
"Cancel": 9985,
"Word": 2343
},
"Flow": {
"Support": 746084,
"About": 0,
"Learn": 0
}
}
function filterBy(val) {
var result = Object.keys(obj).reduce(function(r, e) {
if (e.toLowerCase().indexOf(val) != -1) {
r[e] = obj[e];
} else {
Object.keys(obj[e]).forEach(function(k) {
if (k.toLowerCase().indexOf(val) != -1) {
var object = {}
object[k] = obj[e][k];
r[e] = object;
}
})
}
return r;
}, {})
return result;
}
console.log(filterBy('ange'))
console.log(filterBy('flo'))
console.log(filterBy('wor'))
With the filter method I think you mean the Array#filter function. This doesn't work for objects.
Anyway, a solution for your input data could look like this:
function filterObjects(objects, filter) {
filter = filter.toLowerCase();
var filtered = {};
var keys = Object.keys(objects);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
if (objects.hasOwnProperty(key) === true) {
var object = objects[key];
var objectAsString = JSON.stringify(object).toLowerCase();
if (key.toLowerCase().indexOf(filter) > -1 || objectAsString.indexOf(filter) > -1) {
filtered[key] = object;
}
}
}
return filtered;
}
I see many topics on this site, but every one deal with single Array.
My need is to convert every object with number as key to array.
For exemple,
I have an object like :
{
"parent":{
"0":{
"child":false
},
"1":{
"child":false
},
"4": {
"child":false
}
}
}
And i would like
{
"parent": [
{
"child":false
},
{
"child":false
},
null,
null,
{
"child":false
}
]
}
This is an exemple, my object can be really deep and content many object like this, so i need a generic function.
UPDATE
My try sor far using code of #Nenad Vracar :
function recursiveIteration(object) {
var newob = {};
for (var property in object) {
if (object.hasOwnProperty(property)) {
if (typeof object[property] == "object"){
var result = {};
var keys = Object.keys(object[property]);
if ($.isNumeric(keys[0])) {
console.log("======> "+property+" is table");
for (var i = 0; i <= keys[keys.length - 1]; i++) {
if (keys.indexOf(i.toString()) != -1) {
result[property] = (result[property] || []).concat(object[property][i]);
} else {
result[property] = (result[property] || []).concat(null);
}
}
newob[property] = result;
recursiveIteration(object[property]);
}
newob[property] = object[property];
recursiveIteration(object[property]);
}else{
newob[property] = object[property];
}
}
}
return newob;
}
And the JSFiddle for live try
Thanks you guys !
I think this is what you want:
var data = {
"parent": {
"0": {
"child": false
},
"1": {
"child": false
},
"4": {
"child": false
}
}
};
var convert = function(data) {
// not an object, return value
if (data === null || typeof data !== 'object')
return data;
var indices = Object.keys(data);
// convert children
for (var i = 0; i < indices.length; i++)
data[indices[i]] = convert(data[indices[i]]);
// check if all indices are integers
var isArray = true;
for (var i = 0; i < indices.length; i++) {
if (Math.floor(indices[i]) != indices[i] || !$.isNumeric(indices[i])) {
isArray = false;
break;
}
}
// all are not integers
if (!isArray) {
return data;
}
// all are integers, convert to array
else {
var arr = [];
for (var i = 0, n = Math.max.apply(null, indices); i <= n; i++) {
if (indices.indexOf(i.toString()) === -1)
arr.push(null);
else
arr.push(data[i]);
}
return arr;
}
};
console.log( convert(data) );
Here is a working jsfiddle with the data you provided in the update.
You can do this with Object.keys() and one for loop
var data = {"parent":{"0":{"child":false},"1":{"child":false},"4":{"child":false}}}, result = {}
var keys = Object.keys(data.parent);
for (var i = 0; i <= keys[keys.length - 1]; i++) {
if (keys.indexOf(i.toString()) != -1) {
result.parent = (result.parent || []).concat(data.parent[i]);
} else {
result.parent = (result.parent || []).concat(null);
}
}
console.log(result)
You might achieve this job with a very simple recursive Object method as follows. Any valid nested object (including arrays) within an object structure will be converted into an array, in which the properties are replaced with indices and values are replaced by items.
Object.prototype.valueToItem = function(){
return Object.keys(this).map(e => typeof this[e] === "object" &&
this[e] !== null &&
!Array.isArray(this[e]) ? this[e].valueToItem()
: this[e]);
};
var o = { name: "terrible",
lastname: "godenhorn",
cars: ["red barchetta", "blue stingray"],
age: 52,
child: { name: "horrible",
lastname: "godenhorn",
cars: ["fiat 124", "tata"],
age: 24,
child:{ name: "badluck",
lastname: "godenhorn",
cars: ["lamborghini countach"],
age: 2,
child: null}}},
a = o.valueToItem();
console.log(a);
Ok modified to the OP's conditions but still generic as much as it can be.
Object.prototype.valueToItem = function(){
var keys = Object.keys(this);
return keys.reduce((p,c) => typeof this[c] === "object" &&
this[c] !== null &&
!Array.isArray(this[c]) ? keys.every(k => Number.isInteger(k*1)) ? (p[c] = this[c].valueToItem(),p)
: this[c].valueToItem()
: this
,new Array(~~Math.max(...keys)).fill(null));
};
var o = {
parent: {
0: {
child : false
},
1: {
child : false
},
4: {
child : {
0: {
child : false
},
3: {
child : false
},
5: {
child : false
}
}
}
}
};
a = o.valueToItem();
console.log(JSON.stringify(a,null,4));
I'm extending the haruki template to support sub parameters.
My JSDoc comment is:
/**
* #constructor Foobar
* param {Object} firstLevel
* param {Object} [firstLevel.secondLevel]
* param {Object} [firstLevel.secondLevel.thirdLevel]
*/
By default, haruki will export a flat array of parameters like this:
[
{ name: 'firstLevel' },
{ name: '[firstLevel.secondLevel]' },
{ name: '[firstLevel.secondLevel.thirdLevel]' }
]
But I need to get an output like this:
[
{
name: 'firstLevel',
parameters: [
{
name: 'secondLevel',
parameters: [
{ name: 'thirdLevel' }
]
}
]
}
My idea was to create an Object and then convert it to Array, doing so I can easily access to the nested parameters.
But I can't find a solution to the recursiveness problem...
My attempt is the one below:
function subParam(paramsObj, names, paramObj) {
if (names.length === 1) {
paramsObj[names[0]] = paramObj;
} else {
paramsObj[names[0]].parameters[names[1]] = paramObj;
}
}
if (element.params) {
var params = {};
for (i = 0, len = element.params.length; i < len; i++) {
var names = element.params[i].name.replace(/\[|\]/g, '').split('.');
var obj = {
'name': element.params[i].name,
'type': element.params[i].type? element.params[i].type.names : [],
'description': element.params[i].description || '',
'default': hasOwnProp.call(element.params[i], 'defaultvalue') ? element.params[i].defaultvalue : '',
'optional': typeof element.params[i].optional === 'boolean'? element.params[i].optional : '',
'nullable': typeof element.params[i].nullable === 'boolean'? element.params[i].nullable : ''
};
subParam(params, names, obj);
}
// convert object to array somehow
}
Ideas?
In JavaScript, key-value pairs where key is unique are best suited for Object and not Array.
Create your tree in an Object, then re-structure it to your desired Array
function transform(data) {
var o = {}, i, str;
function addPath(path) {
var parts = path.split('.'),
e = o, i = 0;
for (; i < parts.length; ++i) {
e = e[parts[i]] = e[parts[i]] || {};
}
}
function transformPathObject(dir, obj) {
var key, arr = [];
for (key in obj) {
arr.push(transformPathObject(key, obj[key]));
}
obj = {'name': dir};
if (arr.length) obj.parameters = arr;
return obj;
}
for (i = 0; i < data.length; ++i) {
str = data[i].name;
str = str.replace(/^\[(.*)\]$|(.*)/, '$1$2');
addPath(str);
}
return transformPathObject('__root__', o).parameters;
}
Usage
var data = [
{ name: 'firstLevel' },
{ name: '[firstLevel.secondLevel]' },
{ name: '[firstLevel.secondLevel.thirdLevel]' }
];
transform(data);
/*
[
{
"name": "firstLevel",
"parameters": [
{
"name": "secondLevel",
"parameters": [
{
"name": "thirdLevel"
}
]
}
]
}
]
*/
Please note that you didn't show Optional data in your desired output
In this stackoverflow thread, i learnt you can get a object path via a simple string.
Accessing nested JavaScript objects with string key
consider the following:
var person = { name: "somename", personal: { weight: "150", color: "dark" }};
var personWeight = deep_value(person,"personal.weight");
I an trying to construct an array of the object values who are not of type 'object' from my 'person' object.
Hence the array would look like:
[['name', []],['personal.weight', []],['personal.color', []]];
I want them to look in that form because i have further use for it down the road.
That's what I've tried:
var toIterate = { name: "somename", personal: { age: "19", color: "dark" } }
var myArray = [];
$.each(toIterate, recursive);
function recursive(key, value) {
if (key !== null) {
myArray.push([key, []]);
}
else {
$.each(value, recursive);
}
}
console.log(myArray);
Just use recursion to walk the object.
var person = {
name: "somename",
personal: {
weight: "150",
color: "dark",
foo: {
bar: 'bar',
baz: 'baz'
},
empty: {
}
}
};
// however you want to do this
var isobject = function(x){
return Object.prototype.toString.call(x) === '[object Object]';
};
var getkeys = function(obj, prefix){
var keys = Object.keys(obj);
prefix = prefix ? prefix + '.' : '';
return keys.reduce(function(result, key){
if(isobject(obj[key])){
result = result.concat(getkeys(obj[key], prefix + key));
}else{
result.push(prefix + key);
}
return result;
}, []);
};
var keys = getkeys(person);
document.body.innerHTML = '<pre>' + JSON.stringify(keys) + '</pre>';
Then use Array.prototype.map to massage the array of keys into your preferred format.
Note the behaviour with person.personal.empty.
This does seem like a strange way to store an object's keys. I wonder what your 'further use for it down the road' is.
This is what worked for me. Note that, a raw map is created first and then mapped to an join the items in the Array with ..
var toIterate = {
name: "somename",
personal: {
age: "19",
color: "dark"
}
};
console.log(getObjPath(toIterate).map(item => item.join('.')));
function isObject(x) {
return Object.prototype.toString.call(x) === '[object Object]';
};
function getObjPath(obj, pathArray, busArray) {
pathArray = pathArray ? pathArray : [];
if (isObject(obj)) {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (isObject(obj[key])) {
busArray = busArray ? bussArray : [];
busArray.push(key);
getObjPath(obj[key], pathArray, busArray);
} else {
if (busArray) {
pathArray.push(busArray.concat([key]));
} else {
pathArray.push([key]);
}
}
}
}
}
return pathArray;
}
Good Luck...
I found the following solution on github.
https://github.com/mariocasciaro/object-path