Format a javascript object into a specific structure - javascript

i have a javascript object as follows
obj = {"account_id-0":null,"option_item_id-0":1,"value-0":"wer","account_id-1":null,"option_item_id-1":2,"value-1":"kkk","account_id-2":null,"option_item_id-2":3,"value-2":"qqqqq"
....
"account_id-n":null,"option_item_id-n":6,"value-n":"see"
}
From the above object, i need to create the following structure
{"0": {
account_id: null,
option_item_id: 1,
value: "wer"
},
"1": {
account_id: null,
option_item_id: 2,
value: "kkk"
},
"2": {
account_id: null,
option_item_id: 2,
value: "qqqqq"
},
.
.
.
"n": {
account_id: null,
option_item_id: 6,
value: "see"
}
}
Any idea on how to implement this?

You can iterate through the all the keys, and use Array#reduce to contruct the resultant object.
let obj = {
"account_id-0": null,
"option_item_id-0": 1,
"value-0": "wer",
"account_id-1": null,
"option_item_id-1": 2,
"value-1": "kkk",
"account_id-2": null,
"option_item_id-2": 3,
"value-2": "qqqqq",
"account_id-n": null,
"option_item_id-n": 6,
"value-0": "see"
};
let result = Object.keys(obj).reduce((res, item) => {
let [key, index] = item.split('-');
if (!res[index]) {
res[index] = {};
}
res[index][key] = obj[item];
return res;
}, {});
console.log(result);

var obj = {
"account_id-0": null,
"option_item_id-0": 1,
"value-0": "wer",
"account_id-1": null,
"option_item_id-1": 2,
"value-1": "kkk",
"account_id-2": null,
"option_item_id-2": 3,
"value-2": "qqqqq"
};
var props = [];
function getObj(ind) {
for (var p in props) {
if (ind === p) {
return props[p];
}
}
}
for (var prop in obj) {
var parts = prop.split('-');
var key = parts[0];
var indx = parts[1];
var tmp = getObj(indx);
if (tmp == undefined) {
var x = {};
x[indx] = {};
x[indx][key] = obj[prop];
props.push(x);
} else {
tmp[indx][key] = obj[prop];
}
}
console.log(props);
This should be the straight forward way of maniplulating the object array with simple split() function.

Try this:
var keys = Object.keys(obj), i = 0
var arr = [], o = {}
for(var k in keys) {
if(keys[k].match(/\d*$/m) == i) {
o[keys[k].replace(/-\d*$/m,'')] = obj[keys[k]]
} else {
i++
arr.push(o)
o = {}
}
}
Here I am using an array instead of an object with the keys "0", "1", " 2", ... "n". I think it's way more convenient.

Related

JavaScript - Creating a deepSet() with multiple-level Array support

So I need a deepSet() function in my React application and I know there are dozens of libraries available for that. However, my requirements are beyond that of the standard deepSet(). My function has to be able to support Arrays, and multiple Arrays in the path.
Example, simple deepSet()
var obj = { one: { two: {three: 'a'}} };
deepSet(obj, 'one.two.three', 'yay');
// {one: {two: { three: 'yay' } } }
What I need it to support (and have working)
var obj = { one: { two: [{three: 'a'}, {three: 'a'}] } };
deepSet(obj, 'one.two[].three', 'yay');
// { one: { two: [{three: 'yay'}, {three: 'yay'}] }};
What I also need it to support, and DO NOT have working yet
var obj = { one: { two: [{three: [{four:'a'}, {four:'b'}]}, {three: [{four:'a'}, {four:'b'}]}]}};
deepSet(obj, 'one.two[].three[].four', 'yay');
// { one: { two: [{three: [{four:'yay'}, {four:'yay'}]}, {three: [{four:'yay'}, {four:'yay'}]}]}};
My problem is that I can't figure out how to get that next level of arrays and iterate over them. I think a recursive approach is best here, but I can't figure that out to handle 2 or more Arrays. I've spent a few hours on this and am turning to SO for help.
Here's the algorithm I have so far, that supports 0 and 1 level of Arrays.
const deepSet = (object, path, value) => {
let fields = path.split('.');
for (let i=0; i<fields.length; i++) {
let f = fields[i];
if (f.indexOf("[]") > -1) {
let arrayfield = f.replace('[]', '');
f = fields[++i];
object[arrayfield].forEach((el, idx) => {
if (isEmpty(el[f])) {
el[f]= {};
}
if (i === fields.length - 1) {
el[f] = value;
}
});
object = object[arrayfield];
}
else {
if (isEmpty(object[f])) {
object[f] = {};
}
if (i === fields.length - 1) {
object[f] = value;
}
object = object[f];
}
};
}
You need to walk through branches as you find these, so that each branch entry becomes a new deepSet.
Example
const deepSet = (obj, path, value) => {
const re = /(\.|\[\]\.)/g;
let i = 0, match = null;
while (match = re.exec(path)) {
const sep = match[0];
const {length} = sep;
const {index} = match;
obj = obj[path.slice(i, index)];
i = index + length;
if (1 < length) {
path = path.slice(i);
obj.forEach(obj => {
deepSet(obj, path, value);
});
return;
}
}
obj[path.slice(i)] = value;
};
var obj = { one: { two: [{three: [{four:'a'}, {four:'b'}]}, {three: [{four:'a'}, {four:'b'}]}]}};
deepSet(obj, 'one.two[].three[].four', 'yay');
This will produce the expected result:
{
"one": {
"two": [
{
"three": [
{
"four": "yay"
},
{
"four": "yay"
}
]
},
{
"three": [
{
"four": "yay"
},
{
"four": "yay"
}
]
}
]
}
}
Hope it helps or, at least, it gave you a hint 👋
You could take a recursive approach
const
deepSet = (object, path, value) => {
let [key, ...keys] = path.split('.');
if (key.endsWith('[]')) {
object = object[key.slice(0, -2)];
Object.keys(object).forEach(k => {
if (keys.length) deepSet(object[k], keys.join('.'), value);
else object[k] = value;
});
} else {
if (keys.length) deepSet(object[key], keys.join('.'), value);
else object[key] = value;
}
},
object = { one: { two: [{ three: [{ four: 'a' }, { four: 'b' }] }, { three: [{ four: 'a' }, { four: 'b' }] }] } };
deepSet(object, 'one.two[].three[].four', 'yay');
console.log(object);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Convert an array to json object by javascript

I am stuck to solve this problem.
Convert an array below
var input = [
'animal/mammal/dog',
'animal/mammal/cat/tiger',
'animal/mammal/cat/lion',
'animal/mammal/elephant',
'animal/reptile',
'plant/sunflower'
]
to json Object
var expectedResult = {
"animal": {
"mammal": {
"dog": true,
"cat": {
"tiger": true,
"lion": true
},
"elephant": true
},
"reptile": true
},
"plant": {
"sunflower": true
}
}
Which data structure and algorithm can I apply for it?
Thanks
You need to first split each element to convert to array
using reverse reduce method you can convert them to object.
And your last step is merge this objects.
Lodash.js merge method is an one way to merge them.
var input = ['animal/mammal/dog','animal/mammal/cat/tiger','animal/mammal/cat/lion', 'animal/mammal/elephant','animal/reptile', 'plant/sunflower']
var finalbyLodash={}
input.forEach(x=>{
const keys = x.split("/");
const result = keys.reverse().reduce((res, key) => ({[key]: res}), true);
finalbyLodash = _.merge({}, finalbyLodash, result);
});
console.log(finalbyLodash);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.js"></script>
To make the process more understandable, break the problem down into pieces.
The first step is convert each string into something we can use, converting this:
"animal/mammal/dog"
into this:
[ "animal", "mammal", "dog" ]
That's an array of property names needed to build the final object.
Two functions will accomplish this for you, String.prototype.split() to split the string into an array, and Array.prototype.map() to transform each of the array elements:
let splitIntoNames = input.map(str => str.split('/'));
The intermediate result is this:
[
[ "animal", "mammal", "dog" ],
[ "animal", "mammal", "cat", "tiger" ],
[ "animal", "mammal", "cat", "lion" ],
[ "animal", "mammal", "elephant" ],
[ "animal", "reptile" ],
[ "plant", "sunflower" ]
]
Next step is to iterate over each array, using Array.prototype.forEach() to add properties to the object. You could add properties to the object with a for loop, but let's do that with a recursive function addName():
function addName(element, list, index) {
if (index >= list.length) {
return;
}
let name = list[index];
let isEndOfList = index === list.length - 1;
element[name] = element[name] || (isEndOfList ? true : {});
addName(element[name], list, index + 1);
}
let result = {};
splitIntoNames.forEach((list) => {
addName(result, list, 0);
});
The result:
result: {
"animal": {
"mammal": {
"dog": true,
"cat": {
"tiger": true,
"lion": true
},
"elephant": true
},
"reptile": true
},
"plant": {
"sunflower": true
}
}
const input = [
"animal/mammal/dog",
"animal/mammal/cat/tiger",
"animal/mammal/cat/lion",
"animal/mammal/elephant",
"animal/reptile",
"plant/sunflower",
];
let splitIntoNames = input.map((str) => str.split("/"));
console.log("splitIntoNames:", JSON.stringify(splitIntoNames, null, 2));
function addName(element, list, index) {
if (index >= list.length) {
return;
}
let name = list[index];
let isEndOfList = index === list.length - 1;
element[name] = element[name] || (isEndOfList ? true : {});
addName(element[name], list, index + 1);
}
let result = {};
splitIntoNames.forEach((list) => {
addName(result, list, 0);
});
console.log("result:", JSON.stringify(result, null, 2));
You can create a function that will slice every element from the array by "/" than you put the results into a variable and than just mount the Json. I mean something like that below:
window.onload = function() {
var expectedResult;
var input = [
'animal/mammal/dog',
'animal/mammal/cat/tiger',
'animal/mammal/cat/lion',
'animal/mammal/elephant',
'animal/reptile',
'plant/sunflower'
]
input.forEach(element => {
var data = element.split('/');
var dog = data[2] === 'dog' ? true : false
var tiger = data[2] === 'cat' && data[3] === 'tiger' ? true : false
var lion = data[2] === 'cat' && data[3] === 'lion' ? true : false
expectedResult = {
data[0]: {
data[1]: {
"dog": dog,
"cat": {
"tiger": tiger,
"lion": lion
}
}
}
}
})
}
Late to the party, here is my try. I'm implmenting recursive approach:
var input = ['animal/mammal/dog', 'animal/mammal/cat/tiger', 'animal/mammal/cat/lion', 'animal/mammal/elephant', 'animal/reptile', 'plant/sunflower'];
result = (buildObj = (array, Obj = {}) => {
array.forEach((val) => {
keys = val.split('/');
(nestedFn = (object) => {
outKey = keys.shift();
object[outKey] = object[outKey] || {};
if (keys.length == 0) object[outKey] = true;
if (keys.length > 0) nestedFn(object[outKey]);
})(Obj)
})
return Obj;
})(input);
console.log(result);
I try with array reduce, hope it help
let input = [
"animal/mammal/dog",
"animal/mammal/cat/tiger",
"animal/mammal/cat/lion",
"animal/elephant",
"animal/reptile",
"plant/sunflower",
];
let convertInput = (i = []) =>
i.reduce((prev, currItem = "") => {
let pointer = prev;
currItem.split("/").reduce((prevPre, currPre, preIdx, arrPre) => {
if (!pointer[currPre]) {
pointer[currPre] = preIdx === arrPre.length - 1 ? true : {};
}
pointer = pointer[currPre];
}, {});
return prev;
}, {});
console.log(JSON.stringify(convertInput(input), null, 4));

Sorting JSON Array by a double nested value?

I am unable to find a reasonable solution as I am pulling JSON data from firebase and pulling it from node.js into an html file. I want to sort my data via a property called "value" by not sure how to access a sub-sub-value to sort by in JQuery and am wondering if someone could help lead me in the right direction.
{
key: "a",
{
key: "ab",
{
value: 2
}
key: "ac",
{
value: 0
}
}
},
{
key: "b",
{
key: "bb",
{
value: 1
}
}
},
Output:
[{ac}, {bb}, {ab}]
Both your input and desired output are expressed in an invalid notation (both in JSON and JavaScript syntax), so I'll have to make some assumptions.
You could use this recursive function, which will find all nested value properties, and collect those values together with the names of the parent properties in which they occur. Finally those pairs of data (parent key and value) are sorted:
function collectValues(obj, name) {
return Object.entries(obj).reduce( (acc, [key, value]) => {
return acc.concat(
// recursively look into nested objects:
Object(value) === value ? collectValues(value, key)
// else, when key is 'value', collect that object
: key == 'value' ? [[name, value]]
// otherwise ignore this value
: []
)
}, []);
}
// Sample input
var input = [{
"a": {
"ab": {
value: 2
},
"ac": {
value: 0
}
}
}, {
"b": {
"bb": {
value: 1
}
}
}];
var result = collectValues(input).sort( (a,b) => a[1] - b[1] );
console.log(result);
Mocking up your JSON from the original image:
var data = {
key1: {
"a": { "deliveryshort": "12152017" },
"b": { "deliveryshort": "10122015" },
"c": { "deliveryshort": "11302016" },
"d": { "deliveryshort": "09022014" }
},
key2: {
"a": { "deliveryshort": "10102017" },
"b": { "deliveryshort": "09102017" }
},
};
function parseDate(dateStr) {
var month = "" + dateStr[0] + dateStr[1];
var day = "" + dateStr[2] + dateStr[3];
var year = "" + dateStr[4] + dateStr[5] + dateStr[6] + dateStr[7];
var result = new Date(year, month, day);
return result;
}
function sortBy(data, property, converter) {
var j = new Array();
for (var item in data) {
j.push([item, data[item], converter(data[item][property])]);
}
j.sort(function (a, b) { return a[2] - b[2] });
return j;
}
function sortData(data) {
var d = {};
for (var item in data) {
var sorted = sortBy(data[item], "deliveryshort", function (a) { return parseDate(a); });
/*var normalized = new Array();
for (var i = 0; i < sorted.length; i++) {
var ni = sorted[i];
var key = ni[0];
var obj = ni[1];
normalized[key] = obj;
}*/
d[item] = sorted;
}
console.log(d);
return d;
}
sortData(data);

Javascript/Jquery JSON object to array inside object

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));

How to convert JSON string values to lowercase in Javascript?

I have some JSON data which contains mixture of string and int values. How can I convert all the string values to lowercase?
For example:
{ id: 0, name: "SAMPLe", forms: { formId: 0, id: 0, text: "Sample Text" }}
Desired output:
{ id: 0, name: "sample", forms: { formId: 0, id: 0, text: "sample text" }}
You can use JSON.stringify(), JSON.parse(), typeof
var data = {
id: 0,
name: "SAMPLe",
forms: {
formId: 0,
id: 0,
text: "Sample Text"
}
};
var res = JSON.parse(JSON.stringify(data, function(a, b) {
return typeof b === "string" ? b.toLowerCase() : b
}));
console.log(res)
You need to recurse through the object:
https://jsbin.com/lugokek/1/edit?js,console
var x = { id: 0, name: "SAMPLe", forms: { formId: 0, id: 0, text: "Sample Text" }};
function lower(obj) {
for (var prop in obj) {
if (typeof obj[prop] === 'string') {
obj[prop] = obj[prop].toLowerCase();
}
if (typeof obj[prop] === 'object') {
lower(obj[prop]);
}
}
return obj;
}
console.log(lower(x));
You need to traverse the object.
function lowerStrings(obj) {
for (let attr in obj) {
if (typeof obj[attr] === 'string') {
obj[attr] = obj[attr].toLowerCase();
} else if (typeof obj[attr] === 'object') {
lowerStrings(obj[attr]);
}
}
}
var obj = {
id: 0,
name: "SAMPLe",
forms: { formId: 0, id: 0, text: "Sample Text" }
};
lowerStrings(obj);
console.log(obj);
In my case, I want only the properties convert to lowercase, the value(like password, number...etc) remain the same.
my ajax callback result set is:
result = [{FULL_NAME:xxx}, {}, {}....... {}]
I want it to be:
result = [{full_name:xxx}, {}, {}....... {}]
Here is my working code:
I use mazillar browser native api fetch() instead of old ajax or jquery $get etc.
// ********** must use self = this **************
// this reference vue-app. must pass it to self, then pass into callback function (success call back)
var self = this;
fetch(getUser_url).then(function (response) {
return response.json();
}).then(function (result) {
//------------------------ properties to lowercase ----------------------
// result is upper case, must convert all properties to lowercase,
// however, the value like password or number MUST remain no change.
// result = [{}, {}, {}....... {}]
var result_lower_properties= [];
var arrayLength = result.length;
for (var i = 0; i < arrayLength; i++) {
var obj = result[i];
var obj_lower_properties = {};
for (var prop in obj) {
//console.log(prop.toLowerCase())
//console.log(obj[prop])
obj_lower_properties[prop.toLowerCase()] = obj[prop]
}// for
result_lower_properties.push(obj_lower_properties)
}// for
//---------- ENd -------------- properties to lowercase ----------------------
// must use self.user, do not use this.user,
// because here, this's scope is just the function (result).
// we need this reference to vue-app,
self.user = result_lower_properties; // [{}, {}, {}]
}); // fetch(){}
Use json-case-convertor
https://www.npmjs.com/package/json-case-convertor
const jcc = require('json-case-convertor');
jcc.sentenceCaseValues(jsonData)

Categories

Resources